odex25_standard/odex25_donation/affiliate_management/models/affiliate_visit.py

348 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/>;
#################################################################################
from odoo import models, fields, api, _
import datetime
from datetime import timedelta
from odoo.exceptions import UserError
import logging
_logger = logging.getLogger(__name__)
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 = _('%s records has been invoiced out of %s') % (len(invoice_ids), len(aff_vst))
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'type': 'success',
'message': msg,
'next': {'type': 'ir.actions.act_window_close'},
}
}
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()