From d2b88634cf43a4dfda11e420c92341d8d0222b6d Mon Sep 17 00:00:00 2001 From: Luiz Felipe do Divino Date: Mon, 6 Feb 2023 18:33:52 -0300 Subject: [PATCH 1/5] [ADD] POS cfe xml export at fiscal closing --- l10n_br_pos_cfe/__manifest__.py | 2 + l10n_br_pos_cfe/models/__init__.py | 1 + l10n_br_pos_cfe/models/closing.py | 81 ++++++++++++++++++++++++++ l10n_br_pos_cfe/views/closing_view.xml | 21 +++++++ 4 files changed, 105 insertions(+) create mode 100644 l10n_br_pos_cfe/models/closing.py create mode 100644 l10n_br_pos_cfe/views/closing_view.xml diff --git a/l10n_br_pos_cfe/__manifest__.py b/l10n_br_pos_cfe/__manifest__.py index aa5b68308f32..f0729cf97f17 100644 --- a/l10n_br_pos_cfe/__manifest__.py +++ b/l10n_br_pos_cfe/__manifest__.py @@ -14,6 +14,7 @@ "depends": [ "point_of_sale", "l10n_br_pos", + "l10n_br_fiscal_closing", ], "external_dependencies": { "python": ["satcomum"], @@ -22,6 +23,7 @@ "data/pos_payment_method_data.xml", # Views "views/pos_payment_method_view.xml", + "views/closing_view.xml", # Templates "views/pos_template.xml", ], diff --git a/l10n_br_pos_cfe/models/__init__.py b/l10n_br_pos_cfe/models/__init__.py index 0676d138fe24..f5a2be5329d0 100644 --- a/l10n_br_pos_cfe/models/__init__.py +++ b/l10n_br_pos_cfe/models/__init__.py @@ -4,3 +4,4 @@ from . import pos_payment_method from . import pos_order from . import pos_config +from . import closing diff --git a/l10n_br_pos_cfe/models/closing.py b/l10n_br_pos_cfe/models/closing.py new file mode 100644 index 000000000000..4161600f1866 --- /dev/null +++ b/l10n_br_pos_cfe/models/closing.py @@ -0,0 +1,81 @@ +# © 2023 KMEE INFORMATICA LTDA (https://kmee.com.br) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +import base64 +import logging +import os + +from odoo import _, fields, models +from odoo.exceptions import RedirectWarning + +_logger = logging.getLogger(__name__) + +try: + from erpbrasil.base import misc +except ImportError: + _logger.error("Biblioteca erpbrasil.base não instalada") + + +class FiscalClosing(models.Model): + _inherit = "l10n_br_fiscal.closing" + + document_cfe_pos_ids = fields.One2many( + comodel_name="pos.order", + string="CFe POS Documents", + inverse_name="close_id", + ) + + def _prepare_files(self, temp_dir): + temp_dir = super(FiscalClosing, self)._prepare_files(temp_dir) + date_min, date_max = self._date_range() + orders = self.env["pos.order"].search( + [ + ("company_id", "=", self.company_id.id), + ("date_order", ">=", date_min), + ("date_order", "<=", date_max), + ("state", "not in", ["draft"]), + ("amount_paid", ">=", 0), + ("authorization_file", "!=", False), + ] + ) + + document_path = "/".join( + ["cfe_pos", misc.punctuation_rm(self.company_id.cnpj_cpf)] + ) + + for order in orders: + try: + filename = os.path.join( + temp_dir, document_path, f"{order.document_key}.xml" + ) + if not os.path.exists(os.path.dirname(filename)): + os.makedirs(os.path.dirname(filename)) + + with open(filename, "wb") as file: + file.write(base64.b64decode(order.authorization_file)) + + if order.cancel_document_key: + filename = os.path.join( + temp_dir, document_path, f"{order.cancel_document_key}.xml" + ) + if not os.path.exists(os.path.dirname(filename)): + os.makedirs(os.path.dirname(filename)) + + with open(filename, "wb") as file: + file.write(base64.b64decode(order.cancel_file)) + except OSError as e: + raise RedirectWarning(_("Error!"), _("I/O Error")) from e + except PermissionError as e: + raise RedirectWarning( + _("Error!"), _("Check write permissions in your system temp folder") + ) from e + except Exception: + _logger.error( + _( + "Replication failed: document attachments " + "[id = {}] is not present in the database." + ).format(order.name) + ) + + self.write({"document_cfe_pos_ids": [(6, 0, orders.ids)]}) + + return temp_dir diff --git a/l10n_br_pos_cfe/views/closing_view.xml b/l10n_br_pos_cfe/views/closing_view.xml new file mode 100644 index 000000000000..fdf13d7f77c6 --- /dev/null +++ b/l10n_br_pos_cfe/views/closing_view.xml @@ -0,0 +1,21 @@ + + + + + + l10n_br_fiscal.closing.form (in l10n_br_pos_cfe) + l10n_br_fiscal.closing + + + + + + + + + + + From 93a6f8aaff1c6d5cf1f98d6c0fb8377648a91fd2 Mon Sep 17 00:00:00 2001 From: Luiz Felipe do Divino Date: Thu, 9 Feb 2023 14:50:34 -0300 Subject: [PATCH 2/5] [FIX] Close_id field at pos.order --- l10n_br_pos_cfe/models/pos_order.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/l10n_br_pos_cfe/models/pos_order.py b/l10n_br_pos_cfe/models/pos_order.py index c7fcfd85437a..240bd67fade2 100644 --- a/l10n_br_pos_cfe/models/pos_order.py +++ b/l10n_br_pos_cfe/models/pos_order.py @@ -3,7 +3,7 @@ import logging -from odoo import api, models +from odoo import api, models, fields from odoo.addons.l10n_br_fiscal.constants.fiscal import MODELO_FISCAL_CFE @@ -18,6 +18,9 @@ class PosOrder(models.Model): _inherit = "pos.order" + close_id = fields.Many2one(comodel_name="l10n_br_fiscal.closing", + string="Close ID") + @api.model def _order_fields(self, ui_order): order_fields = super(PosOrder, self)._order_fields(ui_order) From 3d21d1bd58e7c17dad875c4441eeb3bb37523cdf Mon Sep 17 00:00:00 2001 From: Luiz Felipe do Divino Date: Fri, 24 Feb 2023 12:26:09 -0300 Subject: [PATCH 3/5] [FIX] Pos Cfe files pathname --- l10n_br_pos_cfe/models/closing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l10n_br_pos_cfe/models/closing.py b/l10n_br_pos_cfe/models/closing.py index 4161600f1866..5101d2466190 100644 --- a/l10n_br_pos_cfe/models/closing.py +++ b/l10n_br_pos_cfe/models/closing.py @@ -39,7 +39,7 @@ def _prepare_files(self, temp_dir): ) document_path = "/".join( - ["cfe_pos", misc.punctuation_rm(self.company_id.cnpj_cpf)] + [misc.punctuation_rm(self.company_id.cnpj_cpf), "cfe_pos"] ) for order in orders: From c0bac801fba9566cb4062284360b9cc597de0526 Mon Sep 17 00:00:00 2001 From: Luiz Felipe do Divino Date: Mon, 7 Aug 2023 22:24:34 -0300 Subject: [PATCH 4/5] [FIX] pre-commit --- l10n_br_pos_cfe/models/pos_order.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/l10n_br_pos_cfe/models/pos_order.py b/l10n_br_pos_cfe/models/pos_order.py index 240bd67fade2..16f604f40ed8 100644 --- a/l10n_br_pos_cfe/models/pos_order.py +++ b/l10n_br_pos_cfe/models/pos_order.py @@ -3,7 +3,7 @@ import logging -from odoo import api, models, fields +from odoo import api, fields, models from odoo.addons.l10n_br_fiscal.constants.fiscal import MODELO_FISCAL_CFE @@ -18,8 +18,7 @@ class PosOrder(models.Model): _inherit = "pos.order" - close_id = fields.Many2one(comodel_name="l10n_br_fiscal.closing", - string="Close ID") + close_id = fields.Many2one(comodel_name="l10n_br_fiscal.closing", string="Close ID") @api.model def _order_fields(self, ui_order): From 0f45d2a38003c5474d299bfd9a04dfc607652b10 Mon Sep 17 00:00:00 2001 From: Luiz Felipe do Divino Date: Mon, 7 Aug 2023 22:24:50 -0300 Subject: [PATCH 5/5] [FIX] Datetime with user timezone to fetch pos.orders --- l10n_br_pos_cfe/models/closing.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/l10n_br_pos_cfe/models/closing.py b/l10n_br_pos_cfe/models/closing.py index 5101d2466190..cf8ac0c638c8 100644 --- a/l10n_br_pos_cfe/models/closing.py +++ b/l10n_br_pos_cfe/models/closing.py @@ -1,8 +1,12 @@ # © 2023 KMEE INFORMATICA LTDA (https://kmee.com.br) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). import base64 +import calendar import logging import os +from datetime import datetime + +import pytz from odoo import _, fields, models from odoo.exceptions import RedirectWarning @@ -26,7 +30,25 @@ class FiscalClosing(models.Model): def _prepare_files(self, temp_dir): temp_dir = super(FiscalClosing, self)._prepare_files(temp_dir) - date_min, date_max = self._date_range() + date_range = calendar.monthrange(int(self.year), int(self.month)) + date_min = datetime( + int(self.year), + int(self.month), + 1, + 0, + 0, + 1, + tzinfo=pytz.timezone(self.env.context["tz"]), + ).astimezone(pytz.utc) + date_max = datetime( + int(self.year), + int(self.month), + date_range[1], + 23, + 59, + 59, + tzinfo=pytz.timezone(self.env.context["tz"]), + ).astimezone(pytz.utc) orders = self.env["pos.order"].search( [ ("company_id", "=", self.company_id.id),