diff --git a/addons/l10n_ke_edi_tremol/models/account_move.py b/addons/l10n_ke_edi_tremol/models/account_move.py
index 51ac1a5a85e..3edbd62ff82 100644
--- a/addons/l10n_ke_edi_tremol/models/account_move.py
+++ b/addons/l10n_ke_edi_tremol/models/account_move.py
@@ -39,28 +39,47 @@ class AccountMove(models.Model):
# -------------------------------------------------------------------------
def _l10n_ke_validate_move(self):
- """ Returns list of errors related to misconfigurations
+ """ Returns list of errors related to misconfigurations per move
Find misconfigurations on the move, the lines of the move, and the
taxes on those lines that would result in rejection by the KRA.
"""
- self.ensure_one()
errors = []
- # The credit note should refer to the control unit number (receipt number) of the original
- # invoice to which it relates.
- if self.move_type == 'out_refund' and not self.reversed_entry_id.l10n_ke_cu_invoice_number:
- errors.append(_("This credit note must reference the previous invoice, and this previous invoice must have already been submitted."))
+ for move in self:
+ move_errors = []
+ if move.country_code != 'KE':
+ move_errors.append(_("This invoice is not a Kenyan invoice and therefore can not be sent to the device."))
- for line in self.invoice_line_ids.filtered(lambda l: l.display_type == 'product'):
- if not line.tax_ids or len(line.tax_ids) > 1:
- errors.append(_("On line %s, you must select one and only one tax.", line.name))
- else:
- if line.tax_ids.amount == 0 and not (line.product_id and line.product_id.l10n_ke_hsn_code and line.product_id.l10n_ke_hsn_name):
- errors.append(_("On line %s, a product with a HS Code and HS Name must be selected, since the tax is 0%% or exempt.", line.name))
+ if move.company_id.currency_id != self.env.ref('base.KES'):
+ move_errors.append(_("This invoice's company currency is not in Kenyan Shillings, conversion to KES is not possible."))
- for tax in self.invoice_line_ids.tax_ids:
- if tax.amount not in (16, 8, 0):
- errors.append(_("Tax '%s' is used, but only taxes of 16%%, 8%%, 0%% or Exempt can be sent. Please reconfigure or change the tax.", tax.name))
+ if move.state != 'posted':
+ move_errors.append(_("This invoice/credit note has not been posted. Please confirm it to continue."))
+
+ if move.move_type not in ('out_refund', 'out_invoice'):
+ move_errors.append(_("The document being sent should be an invoice or credit note."))
+
+ if any([move.l10n_ke_cu_invoice_number, move.l10n_ke_cu_serial_number, move.l10n_ke_cu_qrcode, move.l10n_ke_cu_datetime]):
+ move_errors.append(_("The document already has details related to the fiscal device. Please make sure that the invoice has not already been sent."))
+
+ # The credit note should refer to the control unit number (receipt number) of the original
+ # invoice to which it relates.
+ if move.move_type == 'out_refund' and not move.reversed_entry_id.l10n_ke_cu_invoice_number:
+ move_errors.append(_("This credit note must reference the previous invoice, and this previous invoice must have already been submitted."))
+
+ for line in self.invoice_line_ids.filtered(lambda l: l.display_type == 'product'):
+ if not line.tax_ids or len(line.tax_ids) > 1:
+ move_errors.append(_("On line %s, you must select one and only one tax.", line.name))
+ else:
+ if line.tax_ids.amount == 0 and not (line.product_id and line.product_id.l10n_ke_hsn_code and line.product_id.l10n_ke_hsn_name):
+ move_errors.append(_("On line %s, a product with a HS Code and HS Name must be selected, since the tax is 0%% or exempt.", line.name))
+
+ for tax in move.invoice_line_ids.tax_ids:
+ if tax.amount not in (16, 8, 0):
+ move_errors.append(_("Tax '%s' is used, but only taxes of 16%%, 8%%, 0%% or Exempt can be sent. Please reconfigure or change the tax.", tax.name))
+
+ if move_errors:
+ errors.append((move.name, move_errors))
return errors
@@ -187,6 +206,10 @@ class AccountMove(models.Model):
return msgs
def _l10n_ke_get_cu_messages(self):
+ """ Composes a list of all the command and data parts of the messages
+ required for the fiscal device to open an invoice, add lines and
+ subsequently close it.
+ """
self.ensure_one()
msgs = self._l10n_ke_cu_open_invoice_message()
msgs += self._l10n_ke_cu_lines_messages()
@@ -201,24 +224,38 @@ class AccountMove(models.Model):
# -------------------------------------------------------------------------
def l10n_ke_action_cu_post(self):
- self.ensure_one()
+ """ Returns the client action descriptor dictionary for sending the
+ invoice(s) to the fiscal device.
+ """
# Check the configuration of the invoice
errors = self._l10n_ke_validate_move()
if errors:
- raise UserError(_("Invalid invoice configuration:\n\n%s") % '\n'.join(errors))
+ error_msg = ""
+ for move, error_list in errors:
+ error_list = '\n'.join(error_list)
+ error_msg += _("Invalid invoice configration on %s:\n\n%s", move, error_list)
+ raise UserError(error_msg)
return {
'type': 'ir.actions.client',
'tag': 'post_send',
'params': {
- 'messages': json.dumps([m.decode('cp1251') for m in self._l10n_ke_get_cu_messages()]),
- 'move_id': self.id,
- 'proxy_address': self.company_id.l10n_ke_cu_proxy_address,
- 'company_vat': self.company_id.vat,
+ 'invoices': {
+ move.id: {
+ 'messages': json.dumps([msg.decode('cp1251') for msg in move._l10n_ke_get_cu_messages()]),
+ 'proxy_address': move.company_id.l10n_ke_cu_proxy_address,
+ 'company_vat': move.company_id.vat
+ } for move in self
+ }
}
}
def l10n_ke_cu_response(self, response):
- move = self.browse(response['move_id'])
+ """ Set the fields related to the fiscal device on the invoice.
+
+ This is intended to be utilized by an RPC call from the javascript
+ client action.
+ """
+ move = self.browse(int(response['move_id']))
replies = [msg for msg in response['replies']]
move.update({
'l10n_ke_cu_serial_number': response['serial_number'],
diff --git a/addons/l10n_ke_edi_tremol/static/src/js/send_invoice.js b/addons/l10n_ke_edi_tremol/static/src/js/send_invoice.js
index 8d88d67ac26..a58e5dc7c85 100644
--- a/addons/l10n_ke_edi_tremol/static/src/js/send_invoice.js
+++ b/addons/l10n_ke_edi_tremol/static/src/js/send_invoice.js
@@ -6,28 +6,44 @@ odoo.define('l10n_ke_edi_tremol.action_post_send_invoice', function (require) {
var _t = core._t;
async function post_send(parent, {params}) {
- const move_id = params.move_id;
- await ajax.post(params.proxy_address + '/hw_proxy/l10n_ke_cu_send', params).then(function (res) {
- const res_obj = JSON.parse(res);
- if (res_obj.status != "ok") {
- Dialog.alert(this, "Posting the invoice has failed, with the message: \n" + res_obj.status);
- } else {
- rpc.query({
- model: 'account.move',
- method: 'l10n_ke_cu_response',
- args: [[], {'replies': res_obj.replies, 'serial_number': res_obj.serial_number, 'move_id': move_id}],
- }).then(function () {
- parent.services.action.doAction({
- 'type': 'ir.actions.client',
- 'tag': 'reload',
- });
- }, function () {
- Dialog.alert(this, _t("Error trying to connect to Odoo. Check your internet connection"));
- })
+ let refresh = false;
+ for (let move_id in params.invoices) {
+ try {
+ const res = await ajax.post(
+ params.invoices[move_id].proxy_address + '/hw_proxy/l10n_ke_cu_send', {
+ messages: params.invoices[move_id].messages,
+ company_vat: params.invoices[move_id].company_vat
+ }
+ );
+ const res_obj = JSON.parse(res);
+ if (res_obj.status === "ok") {
+ try {
+ await rpc.query({
+ model: 'account.move',
+ method: 'l10n_ke_cu_response',
+ args: [[], {'replies': res_obj.replies, 'serial_number': res_obj.serial_number, 'move_id': move_id}],
+ });
+ refresh = true;
+ } catch (e) {
+ Dialog.alert(this, _t('Error trying to connect to Odoo. Check your internet connection.\n Error code: ') + e.status);
+ break;
+ }
+ } else {
+ Dialog.alert(this, _t("Posting an invoice has failed, with the message: \n") + res_obj.status);
+ break;
+ }
+ } catch(e) {
+ console.log(e)
+ Dialog.alert(this, _t('Error trying to connect to the middleware. Is the middleware running?\n Error code: ') + e.status);
+ break;
}
- }, function () {
- Dialog.alert(this, _t("Error trying to connect to the middleware. Is the middleware running?"));
- })
+ }
+ if (refresh) {
+ parent.services.action.doAction({
+ 'type': 'ir.actions.client',
+ 'tag': 'reload',
+ });
+ }
}
core.action_registry.add('post_send', post_send);
return post_send;
diff --git a/addons/l10n_ke_edi_tremol/views/account_move_view.xml b/addons/l10n_ke_edi_tremol/views/account_move_view.xml
index 72e74393ecc..92dc801e431 100644
--- a/addons/l10n_ke_edi_tremol/views/account_move_view.xml
+++ b/addons/l10n_ke_edi_tremol/views/account_move_view.xml
@@ -42,6 +42,17 @@
+
+ Send invoices to fiscal device
+
+
+ list
+ code
+
+ action = records.l10n_ke_action_cu_post()
+
+
+
l10n.ke.inherit.account.move.search
account.move