362 lines
18 KiB
Python
362 lines
18 KiB
Python
# -*- coding: utf-8 -*-
|
|
#################################################################################
|
|
# Author : Webkul Software Pvt. Ltd. (<https://webkul.com/>:wink:
|
|
# Copyright(c): 2015-Present Webkul Software Pvt. Ltd.
|
|
# All Rights Reserved.
|
|
#
|
|
#
|
|
#
|
|
# This program is copyright property of the author mentioned above.
|
|
# You can`t redistribute it and/or modify it.
|
|
#
|
|
#
|
|
# You should have received a copy of the License along with this program.
|
|
# If not, see <https://store.webkul.com/license.html/>;
|
|
#################################################################################
|
|
import logging
|
|
_logger = logging.getLogger(__name__)
|
|
from odoo.exceptions import UserError
|
|
from odoo import models, fields,api,_
|
|
from datetime import timedelta
|
|
import datetime
|
|
|
|
class AffiliateVisit(models.Model):
|
|
_name = "affiliate.visit"
|
|
_order = "create_date desc"
|
|
_description = "Affiliate Visit Model"
|
|
|
|
name = fields.Char(string = "Name",readonly='True')
|
|
|
|
# @api.multi
|
|
@api.depends('affiliate_type','type_id')
|
|
def _calc_type_name(self):
|
|
for record in self:
|
|
if record.affiliate_type == 'product':
|
|
record.type_name = record.env['product.template'].browse([record.type_id]).name
|
|
if record.affiliate_type == 'category':
|
|
record.type_name = record.env['product.public.category'].browse([record.type_id]).name
|
|
|
|
|
|
affiliate_method = fields.Selection([("ppc","Pay Per Click"),("pps","Pay Per Sale")],string="Order Report",readonly='True',states={'draft': [('readonly', False)]},help="state of traffic either ppc or pps")
|
|
affiliate_type = fields.Selection([("product","Product"),("category","Category")],string="Affiliate Type",readonly='True',states={'draft': [('readonly', False)]},help="whether the ppc or pps is on product or category")
|
|
type_id = fields.Integer(string='Type Id',readonly='True',states={'draft': [('readonly', False)]},help="Id of product template on which ppc or pps traffic create")
|
|
type_name = fields.Char(string='Type Name',readonly='True',states={'draft': [('readonly', False)]},compute='_calc_type_name',help="Name of the product")
|
|
is_converted = fields.Boolean(string="Is Converted",readonly='True',states={'draft': [('readonly', False)]})
|
|
sales_order_line_id = fields.Many2one("sale.order.line",readonly='True',states={'draft': [('readonly', False)]})
|
|
affiliate_key = fields.Char(string="Key",readonly='True',states={'draft': [('readonly', False)]})
|
|
affiliate_partner_id = fields.Many2one("res.partner",string="Affiliate",readonly='True',states={'draft': [('readonly', False)]})
|
|
url = fields.Char(string="Url",readonly='True',states={'draft': [('readonly', False)]})
|
|
ip_address = fields.Char(readonly='True',states={'draft': [('readonly', False)]})
|
|
currency_id = fields.Many2one('res.currency', 'Currency', required=True,
|
|
default=lambda self: self.env.user.company_id.currency_id.id,readonly='True',states={'draft': [('readonly', False)]})
|
|
convert_date = fields.Datetime(string='Date',readonly='True',states={'draft': [('readonly', False)]})
|
|
price_total = fields.Monetary(string="Sale value",related='sales_order_line_id.price_total',states={'draft': [('readonly', False)]},help="Total sale value of product" )
|
|
unit_price = fields.Float(string="Product Unit Price", related='sales_order_line_id.price_unit', readonly='True',
|
|
states={'draft': [('readonly', False)]},help="price unit of the product")
|
|
commission_amt = fields.Float(readonly='True',states={'draft': [('readonly', False)]})
|
|
affiliate_program_id = fields.Many2one('affiliate.program',string='Program',readonly='True',states={'draft': [('readonly', False)]})
|
|
amt_type = fields.Char(string='Commission Matrix',readonly='True',states={'draft': [('readonly', False)]},help="Commission Matrix on which commission value calculated")
|
|
act_invoice_id = fields.Many2one("account.move", string='Act Invoice id',readonly='True',states={'draft': [('readonly', False)]})
|
|
state = fields.Selection([
|
|
('draft', 'Draft'),
|
|
('cancel', 'Cancel'),
|
|
('confirm', 'Confirm'),
|
|
('invoice', 'Invoiced'),
|
|
('paid', 'Paid'),
|
|
], string='Status', readonly=True, default='draft' )
|
|
product_quantity = fields.Integer(readonly='True',states={'draft': [('readonly', False)]})
|
|
|
|
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
new_visit = None
|
|
for vals in vals_list:
|
|
vals['name'] = self.env['ir.sequence'].next_by_code('affiliate.visit')
|
|
new_visit = super(AffiliateVisit,self).create(vals)
|
|
return new_visit
|
|
|
|
# button on view action
|
|
def action_cancel(self):
|
|
self.state = 'cancel'
|
|
return True
|
|
|
|
# button on view action
|
|
def action_confirm(self):
|
|
check_enable_ppc = self.env['res.config.settings'].sudo().website_constant().get('enable_ppc')
|
|
|
|
if self.affiliate_method != 'ppc' and not self.sales_order_line_id:
|
|
raise UserError("Order is not present in visit %s."%self.name)
|
|
if self.affiliate_method != 'ppc' and not self.price_total:
|
|
raise UserError("Sale value must be greater than zero.")
|
|
|
|
if self.affiliate_method == 'ppc' and (not check_enable_ppc) :
|
|
raise UserError("Pay per click is disable, so you can't confirm it's commission")
|
|
self.state = 'confirm'
|
|
status = self._get_rate(self.affiliate_method , self.affiliate_type, self.type_id )
|
|
if status.get('is_error'):
|
|
raise UserError(status['message'])
|
|
return True
|
|
|
|
|
|
# button on view action
|
|
def action_paid(self):
|
|
self.state = 'paid'
|
|
return True
|
|
|
|
|
|
|
|
# scheduler according to the scheduler define in data automated scheduler
|
|
|
|
@api.model
|
|
def process_scheduler_queue(self):
|
|
users_all = self.env['res.users'].search([('is_affiliate','=',True)])
|
|
ConfigValues = self.env['res.config.settings'].sudo().website_constant()
|
|
payment_day = ConfigValues.get('payment_day')
|
|
threshold_amt = ConfigValues.get('minimum_amt')
|
|
# make the date of current month of setting date
|
|
payment_date = datetime.date(datetime.date.today().year, datetime.date.today().month, payment_day)
|
|
for u in users_all:
|
|
visits = self.search([('state','=','confirm'),('affiliate_partner_id','=',u.partner_id.id)])
|
|
if payment_date and visits:
|
|
visits = visits.filtered(lambda r: fields.Date.from_string(r.create_date) <= payment_date)
|
|
_logger.info("*****filter- visits=%r******",visits)
|
|
|
|
_logger.info("****before******before method***visits**%r*******",visits)
|
|
visits = self.check_enable_ppc_visits(visits)
|
|
# function to filter the visits if ppc is enable or disable accordingly
|
|
_logger.info("*****after*****after method***visits**%r*******",visits)
|
|
total_comm_per_user = 0
|
|
if visits:
|
|
for v in visits:
|
|
total_comm_per_user = total_comm_per_user + v.commission_amt
|
|
if total_comm_per_user >= threshold_amt and payment_date:
|
|
dic={
|
|
'name':"Total earn commission on ppc and pps",
|
|
'quantity':1,
|
|
'price_unit':total_comm_per_user,
|
|
'product_id':ConfigValues.get('aff_product_id'),
|
|
}
|
|
invoice_dict = [
|
|
{
|
|
'invoice_line_ids': [(0, 0, dic)],
|
|
'move_type': 'in_invoice',
|
|
'partner_id':u.partner_id.id,
|
|
'invoice_date':fields.Datetime.now().date()
|
|
}
|
|
]
|
|
|
|
inv_id = self.env['account.move'].create(invoice_dict)
|
|
for v in visits:
|
|
v.state = 'invoice'
|
|
v.act_invoice_id = inv_id.id
|
|
return True
|
|
|
|
|
|
def check_enable_ppc_visits(self,visits):
|
|
check_enable_ppc = self.env['res.config.settings'].sudo().website_constant().get('enable_ppc')
|
|
if check_enable_ppc:
|
|
return visits
|
|
else:
|
|
visits = visits.filtered(lambda v: v.affiliate_method == 'pps')
|
|
return visits
|
|
|
|
|
|
|
|
# method call from server action
|
|
@api.model
|
|
def create_invoice(self):
|
|
# get the value of enable ppc from settings
|
|
ConfigValues = self.env['res.config.settings'].sudo().website_constant()
|
|
check_enable_ppc = ConfigValues.get('enable_ppc')
|
|
aff_vst = self._context.get('active_ids')
|
|
act_invoice = self.env['account.move']
|
|
# check the first visit of context is ppc or pps and enable pps
|
|
affiliate_method_type = self.browse([aff_vst[0]]).affiliate_method
|
|
if affiliate_method_type == 'ppc' and (not check_enable_ppc) :
|
|
raise UserError("Pay per click is disable, so you can't generate it's invoice")
|
|
|
|
invoice_ids =[]
|
|
for v in aff_vst:
|
|
vst = self.browse([v])
|
|
# [[0, 'virtual_754', {'sequence': 10, 'product_id': 36, 'name': '[Deposit] Deposit', 'account_id': 21, 'analytic_account_id': False, 'analytic_tag_ids': [[6, False, []]],
|
|
# 'quantity': 1, 'product_uom_id': 1, 'price_unit': 150, 'discount': 0, 'tax_ids': [[6, False, [1]]]
|
|
|
|
if vst.state == 'confirm':
|
|
# ********** creating invoice line *********************
|
|
if vst.sales_order_line_id:
|
|
dic={
|
|
'name':"Type "+vst.affiliate_type+" on Pay Per Sale ",
|
|
'quantity':1,
|
|
'price_unit':vst.commission_amt,
|
|
# 'move_id':inv_id.id,
|
|
# 'product_id':ConfigValues.get('aff_product_id'),
|
|
}
|
|
else:
|
|
dic={
|
|
'name':"Type "+vst.affiliate_type+" on Pay Per Click ",
|
|
'price_unit':vst.commission_amt,
|
|
'quantity':1,
|
|
# 'product_id':ConfigValues.get('aff_product_id'),
|
|
}
|
|
|
|
invoice_dict = [
|
|
{
|
|
'invoice_line_ids': [(0, 0, dic)],
|
|
'move_type': 'in_invoice',
|
|
'partner_id':vst.affiliate_partner_id.id,
|
|
'invoice_date':fields.Datetime.now().date()
|
|
}]
|
|
line = self.env['account.move'].create(invoice_dict)
|
|
vst.state = 'invoice'
|
|
vst.act_invoice_id = line.id
|
|
invoice_ids.append(line)
|
|
msg = str(len(invoice_ids))+' records has been invoiced out of '+str(len(aff_vst))
|
|
|
|
|
|
partial_id = self.env['wk.wizard.message'].create({'text': msg})
|
|
return {
|
|
'name': "Message",
|
|
'view_mode': 'form',
|
|
'view_id': False,
|
|
'res_model': 'wk.wizard.message',
|
|
'res_id': partial_id.id,
|
|
'type': 'ir.actions.act_window',
|
|
'nodestroy': True,
|
|
'target': 'new',
|
|
}
|
|
|
|
|
|
def _get_rate(self,affiliate_method,affiliate_type,type_id):
|
|
#_get_rate() methods arguments (pps,product,product_id) or (ppc,product,product_id) or (ppc,category,category_id)
|
|
# check product.id in product.template
|
|
# check category.id in product.public.category
|
|
product_exists = False
|
|
category_exists = False
|
|
commission = 0.0
|
|
commission_type = False
|
|
adv_commision_amount = False
|
|
from_currency = self.sales_order_line_id.currency_id
|
|
company = self.env.user.company_id
|
|
response = {}
|
|
if self.affiliate_program_id:
|
|
if affiliate_type == 'product':
|
|
product_exists = self.env['product.template'].browse([type_id])
|
|
if affiliate_type == 'category':
|
|
category_exists = self.env['product.public.category'].browse([type_id])
|
|
|
|
if affiliate_method == 'ppc' and product_exists or category_exists: # pay per click
|
|
commission = from_currency._convert(self.affiliate_program_id.amount_ppc_fixed,self.affiliate_program_id.currency_id, company, fields.Date.today())
|
|
commission_type = 'fixed'
|
|
self.commission_amt = commission
|
|
else:
|
|
# pay per sale
|
|
if affiliate_method == 'pps' and product_exists :
|
|
#for pps_type simple
|
|
if self.affiliate_program_id.pps_type == 's':
|
|
if self.affiliate_program_id.matrix_type == 'f': # fixed
|
|
amt = from_currency._convert(self.affiliate_program_id.amount,self.affiliate_program_id.currency_id, company, fields.Date.today())
|
|
commission = amt * self.product_quantity
|
|
commission_type = 'fixed'
|
|
else:
|
|
if self.affiliate_program_id.matrix_type == 'p' and (not self.affiliate_program_id.amount >100): # percentage
|
|
amt_product = from_currency._convert(self.price_total,self.affiliate_program_id.currency_id, company, fields.Date.today())
|
|
commission = (amt_product * self.affiliate_program_id.amount/100)
|
|
commission_type = 'percentage'
|
|
else:
|
|
response={
|
|
'is_error':1,
|
|
'message':'Percenatge amount is greater than 100',
|
|
}
|
|
else:
|
|
# for pps type advance (advance depends upon price list)
|
|
|
|
if self.affiliate_program_id.pps_type == 'a' and product_exists:#for pps_type advance
|
|
adv_commision_amount,commission,commission_type = self.advance_pps_type_calc()
|
|
# adv_commision_amount = is a amount if advance commission
|
|
# commission = is a amount which is earned by commisiion
|
|
commission = commission * self.product_quantity
|
|
_logger.info("----commision_value-%r--------commision_value_type-%r------",commission,commission_type)
|
|
_logger.info('================advance_pps_type_calc===============')
|
|
if commission and commission_type:
|
|
_logger.info("---22----adv_commision_amount--%r--commision_value-%r--------commision_value_type-%r------",adv_commision_amount,commission,commission_type)
|
|
|
|
else:
|
|
response={
|
|
'is_error':1,
|
|
'message':'No commission Category Found for this product..'
|
|
}
|
|
|
|
|
|
else:
|
|
response={
|
|
'is_error':1,
|
|
'message':'pps_type is advance',
|
|
}
|
|
|
|
else:
|
|
response={
|
|
'is_error':1,
|
|
'message':'Affilite method is niether ppc nor pps or affiliate type is absent(product or category)',
|
|
}
|
|
else:
|
|
|
|
response={
|
|
'is_error':1,
|
|
'message':'Program is absent in visit',
|
|
}
|
|
|
|
if commission:
|
|
self.commission_amt = commission
|
|
# self.amt_type = commission_type
|
|
if commission_type == 'fixed' and affiliate_method == 'ppc':
|
|
self.amt_type = self.affiliate_program_id.currency_id.symbol+ str(commission)
|
|
if commission_type == 'percentage' and affiliate_method == 'ppc':
|
|
self.amt_type = str(self.affiliate_program_id.amount_ppc_fixed)+ '%'
|
|
#for pps
|
|
if commission_type == 'percentage' and self.affiliate_program_id.pps_type == 's':
|
|
self.amt_type = str(self.affiliate_program_id.amount) +"%"
|
|
if commission_type == 'fixed' and affiliate_method == 'pps' and self.affiliate_program_id.pps_type == 's':
|
|
self.amt_type = self.affiliate_program_id.currency_id.symbol + str(commission)
|
|
if commission_type == 'fixed' and affiliate_method == 'pps' and self.affiliate_program_id.pps_type == 'a':
|
|
self.amt_type = self.affiliate_program_id.currency_id.symbol + str(adv_commision_amount)+" advance"
|
|
if commission_type == 'percentage' and affiliate_method == 'pps' and self.affiliate_program_id.pps_type == 'a':
|
|
self.amt_type = str(adv_commision_amount)+"%"+" advance"
|
|
response={
|
|
'is_error':0,
|
|
'message':'Commission successfully added',
|
|
'comm_type':commission_type,
|
|
'comm_amt' : commission
|
|
}
|
|
|
|
else:
|
|
if response.get('is_error') == 1:
|
|
response={
|
|
'is_error':1,
|
|
'message':response.get('message'),
|
|
}
|
|
|
|
return response
|
|
|
|
|
|
|
|
def advance_pps_type_calc(self):
|
|
adv_commision_amount,commision_value,commision_value_type = self.env["advance.commision"].calc_commision_adv(self.affiliate_program_id.advance_commision_id.id, self.type_id , self.unit_price)
|
|
# argument of calc_commision_adv(adv_comm_id, product_id on which commision apply , price of product)
|
|
# return adv_commision_amount ,commision_value, commision_value_type
|
|
_logger.info("---11----adv_commision_amount----commision_value-%r--------commision_value_type-%r------",adv_commision_amount,commision_value,commision_value_type)
|
|
# return commision_value,commision_value_type
|
|
return adv_commision_amount,commision_value,commision_value_type
|
|
|
|
|
|
|
|
|
|
@api.model
|
|
def process_ppc_maturity_scheduler_queue(self):
|
|
_logger.info("-----Inside----process_ppc_maturity_scheduler_queue-----------")
|
|
check_enable_ppc = self.env['res.config.settings'].sudo().website_constant().get('enable_ppc')
|
|
all_ppc_visits = self.search([('affiliate_method','=','ppc'),('state','=','draft')])
|
|
if check_enable_ppc:
|
|
for visit in all_ppc_visits:
|
|
visit.action_confirm()
|