forked from Mapan/odoo17e
246 lines
10 KiB
Python
246 lines
10 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import models, fields, api
|
|
from odoo.exceptions import UserError
|
|
from odoo.tools.translate import _
|
|
from itertools import groupby
|
|
from collections import Counter
|
|
|
|
|
|
class pos_session(models.Model):
|
|
_inherit = "pos.session"
|
|
|
|
total_base_of_measure_tax_a = fields.Monetary(compute="_compute_total_tax")
|
|
total_base_of_measure_tax_b = fields.Monetary(compute="_compute_total_tax")
|
|
total_base_of_measure_tax_c = fields.Monetary(compute="_compute_total_tax")
|
|
total_base_of_measure_tax_d = fields.Monetary(compute="_compute_total_tax")
|
|
|
|
cash_box_opening_number = fields.Integer(
|
|
help="Count the number of cashbox opening during the session"
|
|
)
|
|
users_clocked_ids = fields.Many2many(
|
|
"res.users",
|
|
"users_session_clocking_info",
|
|
string="Users Clocked In",
|
|
help="This is a technical field used for tracking the status of the session for each users.",
|
|
)
|
|
employees_clocked_ids = fields.Many2many(
|
|
"hr.employee",
|
|
"employees_session_clocking_info",
|
|
string="Employees Clocked In",
|
|
help="This is a technical field used for tracking the status of the session for each employees.",
|
|
)
|
|
|
|
pro_forma_sales_number = fields.Integer()
|
|
pro_forma_sales_amount = fields.Monetary()
|
|
pro_forma_refund_number = fields.Integer()
|
|
pro_forma_refund_amount = fields.Monetary()
|
|
|
|
def _pos_data_process(self, loaded_data):
|
|
super()._pos_data_process(loaded_data)
|
|
loaded_data["product_product_work_in"] = self.env.ref(
|
|
"pos_blackbox_be.product_product_work_in"
|
|
).id
|
|
loaded_data["product_product_work_out"] = self.env.ref(
|
|
"pos_blackbox_be.product_product_work_out"
|
|
).id
|
|
|
|
def _loader_params_res_users(self):
|
|
result = super()._loader_params_res_users()
|
|
result["search_params"]["fields"].append("insz_or_bis_number")
|
|
return result
|
|
|
|
def _loader_params_pos_session(self):
|
|
result = super()._loader_params_pos_session()
|
|
result["search_params"]["fields"].append("users_clocked_ids")
|
|
result["search_params"]["fields"].append("employees_clocked_ids")
|
|
return result
|
|
|
|
def _loader_params_res_company(self):
|
|
result = super()._loader_params_res_company()
|
|
result["search_params"]["fields"].append("street")
|
|
return result
|
|
|
|
def _get_pos_ui_hr_employee(self, params):
|
|
result = super()._get_pos_ui_hr_employee(params)
|
|
employee_ids = [employee['id'] for employee in result]
|
|
employees_insz_or_bis_number = self.env['hr.employee'].sudo().browse(employee_ids).read(['insz_or_bis_number'])
|
|
insz_or_bis_number_per_employee_id = {employee['id']: employee['insz_or_bis_number'] for employee in employees_insz_or_bis_number}
|
|
for employee in result:
|
|
employee['insz_or_bis_number'] = insz_or_bis_number_per_employee_id[employee['id']]
|
|
return result
|
|
|
|
def _loader_params_account_tax(self):
|
|
result = super()._loader_params_account_tax()
|
|
result["search_params"]["fields"].append("identification_letter")
|
|
return result
|
|
|
|
@api.depends("order_ids")
|
|
def _compute_total_tax(self):
|
|
for session in self:
|
|
session.total_base_of_measure_tax_a = 0
|
|
session.total_base_of_measure_tax_b = 0
|
|
session.total_base_of_measure_tax_c = 0
|
|
session.total_base_of_measure_tax_d = 0
|
|
for order in session.order_ids:
|
|
session.total_base_of_measure_tax_a += order.blackbox_tax_category_a
|
|
session.total_base_of_measure_tax_b += order.blackbox_tax_category_b
|
|
session.total_base_of_measure_tax_c += order.blackbox_tax_category_c
|
|
session.total_base_of_measure_tax_d += order.blackbox_tax_category_d
|
|
|
|
@api.depends("order_ids")
|
|
def _compute_amount_of_vat_tickets(self):
|
|
for rec in self:
|
|
rec.amount_of_vat_tickets = len(rec.order_ids)
|
|
|
|
def get_user_session_work_status(self, user_id):
|
|
return ((self.config_id.module_pos_hr and user_id in self.employees_clocked_ids.ids) or
|
|
(not self.config_id.module_pos_hr and user_id in self.users_clocked_ids.ids))
|
|
|
|
def increase_cash_box_opening_counter(self):
|
|
self.cash_box_opening_number += 1
|
|
|
|
def set_user_session_work_status(self, user_id, status):
|
|
context = (
|
|
"employees_clocked_ids"
|
|
if self.config_id.module_pos_hr
|
|
else "users_clocked_ids"
|
|
)
|
|
if status:
|
|
self.write({context: [(4, user_id)]})
|
|
else:
|
|
self.write({context: [(3, user_id)]})
|
|
return self[context].ids
|
|
|
|
def _get_sequence_number(self):
|
|
if self.state == "closed":
|
|
return self.env["ir.sequence"].next_by_code(
|
|
"report.point_of_sale.report_saledetails.sequenceZUser"
|
|
)
|
|
return self.env["ir.sequence"].next_by_code(
|
|
"report.point_of_sale.report_saledetails.sequenceXUser"
|
|
)
|
|
|
|
def _get_user_report_data(self):
|
|
def sorted_key_insz(order):
|
|
order.ensure_one()
|
|
if order.employee_id:
|
|
insz = order.sudo().employee_id.insz_or_bis_number
|
|
else:
|
|
insz = order.user_id.insz_or_bis_number
|
|
return [insz, order.date_order]
|
|
|
|
def groupby_key_insz(order):
|
|
if order.employee_id:
|
|
insz = order.sudo().employee_id.insz_or_bis_number
|
|
else:
|
|
insz = order.user_id.insz_or_bis_number
|
|
return [insz]
|
|
|
|
data = {}
|
|
if not self.config_id.certified_blackbox_identifier:
|
|
return data
|
|
|
|
currency = self.currency_id
|
|
|
|
work_in = self.env.ref("pos_blackbox_be.product_product_work_in").id
|
|
work_out = self.env.ref("pos_blackbox_be.product_product_work_out").id
|
|
|
|
for k, g in groupby(sorted(self.order_ids, key=sorted_key_insz), key=groupby_key_insz):
|
|
i = 0
|
|
insz = k[0]
|
|
data[insz] = []
|
|
for order in g:
|
|
if order.lines and order.lines[0].product_id.id == work_in:
|
|
data[insz].append({
|
|
'login': order.employee_id.name if order.employee_id else order.user_id.name,
|
|
'insz_or_bis_number': order.sudo().employee_id.insz_or_bis_number if order.employee_id else order.user_id.insz_or_bis_number,
|
|
'revenue': 0,
|
|
'revenue_per_category': Counter(),
|
|
'first_ticket_time': order.date_order,
|
|
'last_ticket_time': False,
|
|
'fdmIdentifier': order.config_id.certified_blackbox_identifier,
|
|
'cash_rounding_applied': 0,
|
|
})
|
|
|
|
data[insz][i]['revenue'] += order.amount_paid
|
|
data[insz][i]['cash_rounding_applied'] += round(order.amount_total - order.amount_paid, currency.decimal_places)
|
|
total_sold_per_category = {}
|
|
for line in order.lines:
|
|
category_names = line.product_id.pos_categ_ids.mapped('name') or ["None"]
|
|
for category_name in category_names:
|
|
if category_name not in total_sold_per_category:
|
|
total_sold_per_category[category_name] = 0
|
|
total_sold_per_category[category_name] += round(line.price_subtotal_incl, currency.decimal_places)
|
|
|
|
data[insz][i]['revenue_per_category'].update(Counter(total_sold_per_category))
|
|
|
|
if order.lines and order.lines[0].product_id.id == work_out:
|
|
data[insz][i]['last_ticket_time'] = order.date_order
|
|
i = i + 1
|
|
for user in data.values():
|
|
for session in user:
|
|
session['revenue_per_category'] = list(session['revenue_per_category'].items())
|
|
return data
|
|
|
|
def action_report_journal_file(self):
|
|
self.ensure_one()
|
|
pos = self.config_id
|
|
if not pos.iface_fiscal_data_module:
|
|
raise UserError(_("PoS %s is not a certified PoS", pos.name))
|
|
return {
|
|
"type": "ir.actions.act_url",
|
|
"url": "/journal_file/" + str(pos.certified_blackbox_identifier),
|
|
"target": "self",
|
|
}
|
|
|
|
def _get_total_correction(self):
|
|
total_corrections = 0
|
|
|
|
for order in self.order_ids:
|
|
if order.amount_total > 0:
|
|
for line in order.lines:
|
|
if line.price_subtotal_incl < 0:
|
|
total_corrections += line.price_subtotal_incl
|
|
|
|
return round(total_corrections, self.currency_id.decimal_places)
|
|
|
|
def _update_pro_forma(self, order, custom_data=None):
|
|
self.ensure_one()
|
|
if order.state == "draft":
|
|
amount_total = order.amount_total
|
|
if custom_data:
|
|
amount_total = custom_data.get("amount_total", amount_total)
|
|
if amount_total < 0:
|
|
self.pro_forma_refund_number += 1
|
|
self.pro_forma_refund_amount += round(amount_total, self.currency_id.decimal_places)
|
|
else:
|
|
self.pro_forma_sales_number += 1
|
|
self.pro_forma_sales_amount += round(amount_total, self.currency_id.decimal_places)
|
|
|
|
def get_total_discount_positive_negative(self, positive):
|
|
order_ids = self.order_ids.ids
|
|
price_operator = ">=" if positive else "<"
|
|
|
|
orderlines = self.env["pos.order.line"].search(
|
|
[("order_id", "in", order_ids), ("price_subtotal_incl", price_operator, 0), ("discount", ">", 0)]
|
|
)
|
|
|
|
tax_amounts = sum(line.qty * line.price_unit / 100 * line.tax_ids.amount for line in orderlines)
|
|
|
|
amount = sum(
|
|
line.qty * line.price_unit - line.price_subtotal_incl + tax_amounts
|
|
for line in orderlines
|
|
)
|
|
|
|
return round(amount, self.currency_id.decimal_places)
|
|
|
|
def check_everyone_is_clocked_out(self):
|
|
if (
|
|
self.config_id.module_pos_hr and len(self.employees_clocked_ids.ids) > 0
|
|
) or (
|
|
not self.config_id.module_pos_hr and len(self.users_clocked_ids.ids) > 0
|
|
):
|
|
raise UserError(_("You cannot close the POS with employees still clocked in. Please clock them out first."))
|