Files
enterprise-addons/l10n_be_pos_blackbox/models/pos_order.py
T

127 lines
6.4 KiB
Python

from odoo import models, fields, api
from odoo.exceptions import UserError
class PosOrder(models.Model):
_inherit = "pos.order"
# FDM Signature fields (Normal event)
l10n_be_fdm_id = fields.Char(string="FDM ID", readonly=True)
l10n_be_fdm_date_time = fields.Datetime(string="FDM Date Time", readonly=True)
l10n_be_pos_id = fields.Char(string="POS ID", readonly=True)
l10n_be_terminal_id = fields.Char(string="Terminal ID", readonly=True)
l10n_be_device_id = fields.Char(string="Device ID", readonly=True)
l10n_be_pos_date_time = fields.Datetime(string="POS Date Time", readonly=True)
l10n_be_event_label = fields.Char(string="Event Label", readonly=True)
l10n_be_event_counter = fields.Integer(string="Event Counter", readonly=True)
l10n_be_total_counter = fields.Integer(string="Total Counter", readonly=True)
l10n_be_short_signature = fields.Char(string="Short Signature", readonly=True)
l10n_be_verification_url = fields.Char(string="Verification URL", readonly=True)
l10n_be_vat_calc = fields.Json(string="VAT Calculation", readonly=True)
l10n_be_footer = fields.Json(string="VAT receipt footer", readonly=True)
# FDM Signature fields (Invoice event)
l10n_be_I_total_counter = fields.Integer(string="I Total Counter", readonly=True)
l10n_be_I_event_counter = fields.Integer(string="I Event Counter", readonly=True)
l10n_be_I_event_label = fields.Char(string="I Event Label", readonly=True)
l10n_be_I_fdm_date_time = fields.Datetime(string="I FDM Date Time", readonly=True)
l10n_be_I_fdm_id = fields.Char(string="I FDM ID", readonly=True)
l10n_be_last_transaction_by_line = fields.Json(string="Last Transaction By Line uuid", readonly=True)
"""
Details of "l10n_be_last_transaction_by_line"
---------------------------------------------
Stores a snapshot of the last successfully signed transaction state, keyed by
order line UUID. It is used to compute the **delta** between the current order
state and the previously signed state, so that only the necessary corrections
(new, modified, or deleted lines) are sent to the Belgian Blackbox FDM device.
Structure::
{
"<line_uuid>": {
"transLine": {
# Full TransactionLineInput payload as sent to the FDM
"lineType": "SINGLE_PRODUCT" | "COMPOSITE_PRODUCT",
"mainProduct": { ... },
"subProducts": [ ... ], # only for COMPOSITE_PRODUCT
"lineTotal": float,
},
"lineInfos": {
# Snapshot of the pricing state at the time of the last sign
"priceUnit": float, # unit price before discount
"discount": float, # per-line discount percentage
"globalDiscount": float, # order-level global discount percentage
"qty": float, # signed quantity (0 means already corrected)
},
},
...
}
Usage:
Read during ``generateSignOrderInput()`` and ``generateSignCanceledOrderInput()``
to determine which lines are new, modified (price/quantity change), or deleted
since the previous sign call.
Written (via ``order.uiState.transactionLinesMap``) after each successful
``generateSignOrderInput()`` call, so it always reflects the last committed
FDM state.
- **New line** (UUID absent from this field): sent as-is.
- **Modified line** (UUID present but payload differs): a CORRECTION or
PRICE_CHANGE negation line is emitted first, followed by the updated line.
- **Deleted line** (UUID present here but absent from current order): a
CORRECTION negation line is emitted.
- **Cancel order**: all entries with ``lineInfos.qty != 0`` are negated and
sent as CORRECTION lines.
"""
l10n_be_grouping_id = fields.Json(string="Grouping ID by line uuid", readonly=True)
"""
Details of "l10n_be_grouping_id"
--------------------------------
Persists the monotonically-incrementing ``groupingId`` counter and the
per-line grouping-ID assignments across multiple ``signOrder`` calls on the
same order. The Blackbox FDM uses ``groupingId`` values to associate related
price-change entries (e.g. all DISCOUNT lines for the same product) with each
other across separate sign requests.
Structure::
{
"groupingIdCount": int, # global counter; incremented by _nextGroupingId()
"globalDiscountGId": int | None, # shared groupingId for ORDER-scope discount entries
"roundingAdaptationGId": int | None, # shared groupingId for ROUNDING_ADAPTATION entries
"lines": {
"<line_uuid>": {
"unitPriceChangeGId": int | None, # groupingId for UNIT_PRICE_CHANGE entries
"menuDiscountGId": int | None, # groupingId for MENU_DISCOUNT entries
"discountGId": int | None, # groupingId for DISCOUNT_* entries
},
...
}
}
Usage:
- Lazily initialised on first access via ``_getGroupingState()``.
- ``_nextGroupingId()`` atomically increments ``groupingIdCount`` and returns
the new value so each new group gets a unique, stable identifier.
- When a line's pricing attributes change between sign calls
(price-unit, per-line discount, or global discount), the relevant slot
(``unitPriceChangeGId``, ``menuDiscountGId``, ``discountGId``) is reset to
``None``, which forces a fresh ``groupingId`` to be allocated for
the corrected entries — ensuring the FDM can distinguish the new price-change group
from the previously reported one.
- Because this field is stored on the order record (readonly from the UI),
the counter and assignments survive page reloads and re-opens of the same
order.
"""
old_pos_blackbox_be_data = fields.Json(string="Old POS Blackbox BE Data", readonly=True, copy=False)
def _get_cashier(self):
self.ensure_one()
return self.user_id
@api.ondelete(at_uninstall=False)
def unlink_if_blackboxed(self):
for order in self:
if order.config_id.l10n_be_pos_id or order.old_pos_blackbox_be_data:
raise UserError(self.env._("Deleting of registered orders is not allowed."))