1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/pos_blackbox_be/models/pos_order.py
2024-12-10 09:04:09 +07:00

281 lines
12 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 datetime import datetime
class PosOrder(models.Model):
_inherit = "pos.order"
blackbox_date = fields.Char(
"Fiscal Data Module date",
help="Date returned by the Fiscal Data Module.",
readonly=True,
)
blackbox_time = fields.Char(
"Fiscal Data Module time",
help="Time returned by the Fiscal Data Module.",
readonly=True,
)
blackbox_pos_receipt_time = fields.Datetime("Receipt time", readonly=True)
blackbox_ticket_counters = fields.Char(
"Fiscal Data Module ticket counters",
help="Ticket counter returned by the Fiscal Data Module (format: counter / total event type)",
readonly=True,
)
blackbox_unique_fdm_production_number = fields.Char(
"Fiscal Data Module ID",
help="Unique ID of the blackbox that handled this order",
readonly=True,
)
blackbox_vsc_identification_number = fields.Char(
"VAT Signing Card ID",
help="Unique ID of the VAT signing card that handled this order",
readonly=True,
)
blackbox_signature = fields.Char(
"Electronic signature",
help="Electronic signature returned by the Fiscal Data Module",
readonly=True,
)
blackbox_tax_category_a = fields.Monetary(
readonly=True,
string="Total tax for category A",
help="This is the total amount of the 21% tax",
)
blackbox_tax_category_b = fields.Monetary(
readonly=True,
string="Total tax for category B",
help="This is the total amount of the 12% tax",
)
blackbox_tax_category_c = fields.Monetary(
readonly=True,
string="Total tax for category C",
help="This is the total amount of the 6% tax",
)
blackbox_tax_category_d = fields.Monetary(
readonly=True,
string="Total tax for category D",
help="This is the total amount of the 0% tax",
)
plu_hash = fields.Char(help="Eight last characters of PLU hash")
pos_version = fields.Char(help="Version of Odoo that created the order")
def _create_log_description(self, blackbox_order_sequence, custom_data=None):
currency = self.currency_id
lines = []
total = 0
rounding_applied = 0
hash_string = ''
title = ''
if custom_data:
for line in custom_data['lines']:
line = line[2]
product_name = self.env['product.product'].browse(line['product_id']).name
line_description = "{qty} x {product_name}: {price}".format(
qty=line['qty'],
product_name=product_name,
price=round(line['price_subtotal_incl'], currency.decimal_places)
)
if line['discount']:
line_description += " (disc: {discount}%)".format(discount=line['discount'])
lines.append(line_description)
total = round(custom_data['amount_total'], currency.decimal_places) if self.state == "draft" else round(custom_data['amount_paid'], currency.decimal_places)
rounding_applied = 0 if self.state == "draft" else round(custom_data['amount_total'] - custom_data['amount_paid'], currency.decimal_places)
hash_string = custom_data['blackbox_plu_hash']
sale_type = ""
if round(custom_data['amount_total'], currency.decimal_places) > 0:
sale_type = " SALES"
elif round(custom_data['amount_total'], currency.decimal_places) < 0:
sale_type = " REFUNDS"
else:
if len(custom_data['lines']) and custom_data['lines'][0][2]['qty'] >= 0:
sale_type = " SALES"
else:
sale_type = " REFUNDS"
title = ("PRO FORMA" if self.state == "draft" else "NORMAL") + sale_type
else:
for line in self.lines:
line_description = f"{line.qty} x {line.product_id.name}: {round(line.price_subtotal_incl, currency.decimal_places)}"
if line.discount:
line_description += f" (disc: {line.discount}%)"
lines.append(line_description)
total = round(self.amount_total, currency.decimal_places) if self.state == "draft" else round(self.amount_paid, currency.decimal_places)
rounding_applied = 0 if self.state == "draft" else round(self.amount_total - self.amount_paid, currency.decimal_places)
hash_string = self.plu_hash
sale_type = ""
rounded_total_amount = round(self.amount_total, currency.decimal_places)
if rounded_total_amount > 0:
sale_type = " SALES"
elif rounded_total_amount < 0:
sale_type = " REFUNDS"
else:
if len(self.lines) and self.lines[0].qty >= 0:
sale_type = " SALES"
else:
sale_type = " REFUNDS"
title = ("PRO FORMA" if self.state == "draft" else "NORMAL") + sale_type
order_type = self.config_id.name + (' Pro Forma/' if self.state == 'draft' else ' Pos Order/')
description = """
{title}
Date: {create_date}
Internal Ref: {pos_reference}
Sequence: {blackbox_sequence}
Cashier: {cashier_name}
Order lines: {lines}
Total: {total}
Rounding: {rounding_applied}
Ticket Counter: {ticket_counters}
Hash: {hash}
POS Version: {pos_version}
FDM ID: {fdm_id}
POS ID: {config_name}
FDM Identifier: {fdmIdentifier}
""".format(
title=title,
create_date=self.create_date,
cashier_name=self.employee_id.name or self.user_id.name,
lines="\n* " + "\n* ".join(lines),
total=total,
pos_reference=self.pos_reference,
blackbox_sequence=order_type + f"{blackbox_order_sequence:05}",
hash=hash_string,
pos_version=self.pos_version,
ticket_counters=custom_data['blackbox_ticket_counters'] if custom_data else self.blackbox_ticket_counters,
fdm_id=custom_data['blackbox_unique_fdm_production_number'] if custom_data else self.blackbox_unique_fdm_production_number,
config_name=self.config_id.name,
fdmIdentifier=self.config_id.certified_blackbox_identifier,
rounding_applied=rounding_applied,
)
return description
@api.ondelete(at_uninstall=False)
def unlink_if_blackboxed(self):
for order in self:
if order.config_id.iface_fiscal_data_module:
raise UserError(_("Deleting of registered orders is not allowed."))
def write(self, values):
for order in self:
if order.config_id.iface_fiscal_data_module and order.state != "draft":
white_listed_fields = [
"state",
"account_move",
"picking_id",
"invoice_id",
"last_order_preparation_change",
"partner_id",
"to_invoice"
]
for field in values:
if field not in white_listed_fields:
raise UserError(_("Modifying registered orders is not allowed."))
return super(PosOrder, self).write(values)
@api.model
def create_from_ui(self, orders, draft=False):
res = super().create_from_ui(orders, draft)
if self.env['pos.session'].browse(orders[0]['data']['pos_session_id']).config_id.iface_fiscal_data_module:
for order in orders:
for order_res in res:
if not order['data'].get('server_id') and order_res['pos_reference'] == order['data']['name']:
order['data']['server_id'] = order_res['id']
self.create_log(orders)
return res
@api.model
def create_log(self, orders, custom_data=False):
order_ids = self.env['pos.order'].browse([order['data']['server_id'] for order in orders])
orders_bb_sequence = {order['data']['name']: order['data']['blackbox_order_sequence'] for order in orders if order['data'].get('blackbox_order_sequence')}
for order in order_ids:
if order.config_id.iface_fiscal_data_module:
custom_order = order._get_custom_data(order, orders) if custom_data else None
self.env["pos_blackbox_be.log"].sudo().create([{
"action": "create",
"model_name": order._name,
"record_name": order.pos_reference,
"description": order._create_log_description(orders_bb_sequence[order.pos_reference], custom_data=custom_order),
}])
if custom_order:
order.session_id._update_pro_forma(order, custom_order)
else:
order.session_id._update_pro_forma(order)
def _get_custom_data(self, order, orders):
custom_data = {}
for order_data in orders:
if order_data['data']['name'] == order.pos_reference:
custom_data = order_data['data']
break
return custom_data
@api.model
def _order_fields(self, ui_order):
fields = super()._order_fields(ui_order)
config_id = self.env["pos.session"].browse(fields["session_id"]).config_id
if config_id.certified_blackbox_identifier:
date = ui_order.get("blackbox_date")
time = ui_order.get("blackbox_time")
update_fields = {
"blackbox_date": date,
"blackbox_time": time,
"blackbox_pos_receipt_time": datetime.strptime(
date + " " + time, "%d-%m-%Y %H:%M:%S"
) if date else False,
"blackbox_ticket_counters": ui_order.get("blackbox_ticket_counters"),
"blackbox_unique_fdm_production_number": ui_order.get("blackbox_unique_fdm_production_number"),
"blackbox_vsc_identification_number": ui_order.get("blackbox_vsc_identification_number"),
"blackbox_signature": ui_order.get("blackbox_signature"),
"blackbox_tax_category_a": ui_order.get("blackbox_tax_category_a"),
"blackbox_tax_category_b": ui_order.get("blackbox_tax_category_b"),
"blackbox_tax_category_c": ui_order.get("blackbox_tax_category_c"),
"blackbox_tax_category_d": ui_order.get("blackbox_tax_category_d"),
"plu_hash": ui_order.get("blackbox_plu_hash"),
"pos_version": ui_order.get("blackbox_pos_version"),
}
fields.update(update_fields)
return fields
def _refund(self):
for order in self:
if order.config_id.iface_fiscal_data_module:
for line in self.lines:
if line.product_id in [self.env.ref('pos_blackbox_be.product_product_work_in', raise_if_not_found=False), self.env.ref('pos_blackbox_be.product_product_work_out', raise_if_not_found=False)]:
raise UserError(_("Refunding of WORK IN/WORK OUT orders is not allowed."))
return super()._refund()
class PosOrderLine(models.Model):
_inherit = "pos.order.line"
vat_letter = fields.Selection(
[("A", "A"), ("B", "B"), ("C", "C"), ("D", "D")],
help="The VAT letter is related to the amount of the tax. A=21%, B=12%, C=6% and D=0%.",
)
def write(self, values):
if values.get("vat_letter"):
raise UserError(_("Can't modify fields related to the Fiscal Data Module."))
return super(PosOrderLine, self).write(values)