diff --git a/pms_api_rest/datamodels/pms_invoice.py b/pms_api_rest/datamodels/pms_invoice.py index ab5e0779f..b0a65b770 100644 --- a/pms_api_rest/datamodels/pms_invoice.py +++ b/pms_api_rest/datamodels/pms_invoice.py @@ -19,3 +19,4 @@ class PmsAccountInvoiceInfo(Datamodel): saleLines = fields.List(NestedModel("pms.folio.sale.line.info")) narration = fields.String(required=False, allow_none=True) portalUrl = fields.String(required=False, allow_none=True) + moveType = fields.String(required=False, allow_none=True) diff --git a/pms_api_rest/services/pms_folio_service.py b/pms_api_rest/services/pms_folio_service.py index 77e8b4f66..186c7f8f7 100644 --- a/pms_api_rest/services/pms_folio_service.py +++ b/pms_api_rest/services/pms_folio_service.py @@ -588,6 +588,7 @@ class PmsFolioService(Component): else None, moveLines=move_lines if move_lines else None, portalUrl=portal_url, + moveType=move.move_type, ) ) return invoices diff --git a/pms_api_rest/services/pms_invoice_service.py b/pms_api_rest/services/pms_invoice_service.py index 9494659fe..05726df5b 100644 --- a/pms_api_rest/services/pms_invoice_service.py +++ b/pms_api_rest/services/pms_invoice_service.py @@ -1,4 +1,5 @@ from odoo import _, fields +from odoo.exceptions import UserError from odoo.addons.base_rest import restapi from odoo.addons.base_rest_datamodel.restapi import Datamodel @@ -23,14 +24,13 @@ class PmsInvoiceService(Component): input_param=Datamodel("pms.invoice.info"), auth="jwt_api_pms", ) + # flake8: noqa: C901 def update_invoice(self, invoice_id, pms_invoice_info): invoice = self.env["account.move"].browse(invoice_id) - - # Build update values dict - # TODO: Missing data: - # - invoice comment (narration) - # - add new invoice lines (from saleLines selected?) - + if invoice.move_type in ["in_refund", "out_refund"]: + raise UserError(_("You can't update a refund invoice")) + if invoice.payment_state == "reversed": + raise UserError(_("You can't update a reversed invoice")) new_vals = {} if ( pms_invoice_info.partnerId @@ -47,97 +47,73 @@ class PmsInvoiceService(Component): # send to service, the lines that are not sent we assume that # they have been eliminated if pms_invoice_info.moveLines and pms_invoice_info.moveLines is not None: - new_vals["invoice_line_ids"] = [] - for line in invoice.invoice_line_ids: - line_info = [ - item for item in pms_invoice_info.moveLines if item.id == line.id - ] - if line_info: - line_info = line_info[0] - line_values = {} - if line_info.name and line_info.name != line.name: - line_values["name"] = line_info.name - if line_info.quantity and line_info.quantity != line.quantity: - line_values["quantity"] = line_info.quantity - if line_values: - new_vals["invoice_line_ids"].append((1, line.id, line_values)) - else: - new_vals["invoice_line_ids"].append((2, line.id)) - # Get the new lines to add in invoice - new_invoice_lines_info = list( - filter(lambda item: not item.id, pms_invoice_info.moveLines) + cmd_invoice_lines = self._get_invoice_lines_commands( + invoice, pms_invoice_info ) - if new_invoice_lines_info: - partner = ( - self.env["res.partner"].browse(pms_invoice_info.partnerId) - if pms_invoice_info.partnerId - else invoice.partner_id - ) - folios = self.env["pms.folio"].browse( - list( + if cmd_invoice_lines: + new_vals["invoice_line_ids"] = cmd_invoice_lines + if new_vals: + # Update Invoice + # When modifying an invoice, depending on the company's configuration, + # and the invoice stateit will be modified directly or a reverse + # of the current invoice will be created to later create a new one + # with the updated data. + # TODO: to create core pms correct_invoice_policy field + # if invoice.state != "draft" and company.corrective_invoice_policy == "strict": + if invoice.state != "draft": + # invoice create refund + # new invoice with new_vals + move_reversal = ( + self.env["account.move.reversal"] + .with_context(active_model="account.move", active_ids=invoice.ids) + .create( { - self.env["folio.sale.line"] - .browse(line.saleLineId) - .folio_id.id - for line in list( - filter( - lambda item: item.name, - pms_invoice_info.moveLines, - ) - ) + "date": fields.Date.today(), + "reason": _("Invoice modification"), + "refund_method": "modify", } ) ) - new_vals["invoice_line_ids"].extend( - [ - item["invoice_line_ids"] - for item in folios.get_invoice_vals_list( - lines_to_invoice={ - new_invoice_lines_info[i] - .saleLineId: new_invoice_lines_info[i] - .quantity - for i in range(0, len(new_invoice_lines_info)) - }, - partner_invoice_id=partner.id, - ) - ][0] + reversal_action = move_reversal.reverse_moves() + reverse_invoice = self.env["account.move"].browse( + reversal_action["res_id"] ) - if not new_vals: - return invoice.id + invoice = reverse_invoice + invoice.sudo().action_post() + # If change invoice by reversal, and new_vals has invoice_line_ids + # we need to mapp the new invoice lines with the new invoice + reverse_lines = [] + for line in new_vals["invoice_line_ids"]: + origin_line = self.env["account.move.line"].browse(line[1]) + sale_line_id = origin_line.sale_line_ids.id + reverse_line = reverse_invoice.invoice_line_ids.filtered( + lambda item: item.sale_line_ids.id == sale_line_id + and item.price_unit == origin_line.price_unit + and item.quantity == origin_line.quantity + ) + if line[0] == 2: + reverse_lines.append((2, reverse_line[0].id)) + elif line[0] == 1: + reverse_lines.append((1, reverse_line[0].id, line)) + else: + reverse_lines.append(line) + if reverse_lines: + new_vals["invoice_line_ids"] = reverse_lines - # Update Invoice - # When modifying an invoice, depending on the company's configuration, - # and the invoice stateit will be modified directly or a reverse - # of the current invoice will be created to later create a new one - # with the updated data. - # TODO: to create core pms correct_invoice_policy field - # if invoice.state != "draft" and company.corrective_invoice_policy == "strict": - if invoice.state != "draft": - # invoice create refund - # new invoice with new_vals - move_reversal = ( - self.env["account.move.reversal"] - .with_context(active_model="account.move", active_ids=invoice.ids) - .create( - { - "date": fields.Date.today(), - "reason": _("Invoice modification"), - "refund_method": "modify", - } - ) - ) - reversal_action = move_reversal.reverse_moves() - reverse_invoice = self.env["account.move"].browse(reversal_action["res_id"]) - invoice = reverse_invoice - - invoice = self._direct_move_update(invoice, new_vals) - # Update invoice lines name - for item in pms_invoice_info.moveLines: - if item.saleLineId in invoice.invoice_line_ids.mapped("folio_line_ids.id"): - invoice_line = invoice.invoice_line_ids.filtered( - lambda r: item.saleLineId in r.folio_line_ids.ids - ) - invoice_line.write({"name": item.name}) + invoice = self._direct_move_update(invoice, new_vals) + # Update invoice lines name + for item in pms_invoice_info.moveLines: + if item.saleLineId in invoice.invoice_line_ids.mapped( + "folio_line_ids.id" + ): + invoice_line = invoice.invoice_line_ids.filtered( + lambda r: item.saleLineId in r.folio_line_ids.ids + ) + invoice_line.write({"name": item.name}) + if pms_invoice_info.narration is not None: + invoice.write({"narration": pms_invoice_info.narration}) + if invoice.state == "draft" and pms_invoice_info.state == "confirm": + invoice.action_post() return invoice.id def _direct_move_update(self, invoice, new_vals): @@ -185,3 +161,59 @@ class PmsInvoiceService(Component): } template.send_mail(invoice.id, force_send=True, email_values=email_values) return True + + def _get_invoice_lines_commands(self, invoice, pms_invoice_info): + cmd_invoice_lines = [] + for line in invoice.invoice_line_ids: + line_info = [ + item for item in pms_invoice_info.moveLines if item.id == line.id + ] + if line_info: + line_info = line_info[0] + line_values = {} + if line_info.name and line_info.name != line.name: + line_values["name"] = line_info.name + if line_info.quantity and line_info.quantity != line.quantity: + line_values["quantity"] = line_info.quantity + if line_values: + cmd_invoice_lines.append((1, line.id, line_values)) + else: + cmd_invoice_lines.append((2, line.id)) + # Get the new lines to add in invoice + new_invoice_lines_info = list( + filter(lambda item: not item.id, pms_invoice_info.moveLines) + ) + if new_invoice_lines_info: + partner = ( + self.env["res.partner"].browse(pms_invoice_info.partnerId) + if pms_invoice_info.partnerId + else invoice.partner_id + ) + folios = self.env["pms.folio"].browse( + list( + { + self.env["folio.sale.line"].browse(line.saleLineId).folio_id.id + for line in list( + filter( + lambda item: item.name, + pms_invoice_info.moveLines, + ) + ) + } + ) + ) + cmd_invoice_lines.extend( + [ + item["invoice_line_ids"] + for item in folios.get_invoice_vals_list( + lines_to_invoice={ + new_invoice_lines_info[i] + .saleLineId: new_invoice_lines_info[i] + .quantity + for i in range(0, len(new_invoice_lines_info)) + }, + partner_invoice_id=partner.id, + ) + ][0] + ) + return cmd_invoice_lines