diff --git a/pms_api_rest/datamodels/__init__.py b/pms_api_rest/datamodels/__init__.py index 235fdeb3f..9128d5a9d 100644 --- a/pms_api_rest/datamodels/__init__.py +++ b/pms_api_rest/datamodels/__init__.py @@ -15,7 +15,7 @@ from . import pms_partner from . import pms_property from . import pms_account_journal from . import pms_account_payment -from . import pms_account_move +from . import pms_invoice from . import pms_user diff --git a/pms_api_rest/datamodels/pms_account_payment.py b/pms_api_rest/datamodels/pms_account_payment.py index 45025b669..fbf96adcb 100644 --- a/pms_api_rest/datamodels/pms_account_payment.py +++ b/pms_api_rest/datamodels/pms_account_payment.py @@ -11,14 +11,5 @@ class PmsPaymentInfo(Datamodel): date = fields.String(required=False, allow_none=True) paymentType = fields.String(required=False, allow_none=True) reference = fields.String(required=False, allow_none=True) - - -class PmsAccountPaymentInfo(Datamodel): - _name = "pms.account.payment.short.info" - id = fields.Integer(required=False, allow_none=True) - date = fields.String(required=False, allow_none=True) - journalId = fields.Integer(required=False, allow_none=True) - amount = fields.Float(required=False, allow_none=True) partnerId = fields.Integer(required=False, allow_none=True) - reference = fields.String(required=False, allow_none=True) reservationIds = fields.List(fields.Integer(), required=False) diff --git a/pms_api_rest/datamodels/pms_account_move.py b/pms_api_rest/datamodels/pms_invoice.py similarity index 71% rename from pms_api_rest/datamodels/pms_account_move.py rename to pms_api_rest/datamodels/pms_invoice.py index a09d8edc8..b09fa74a1 100644 --- a/pms_api_rest/datamodels/pms_account_move.py +++ b/pms_api_rest/datamodels/pms_invoice.py @@ -4,13 +4,16 @@ from odoo.addons.datamodel.core import Datamodel from odoo.addons.datamodel.fields import NestedModel -class PmsAccountMoveInfo(Datamodel): - _name = "pms.account.move.info" +class PmsAccountInvoiceInfo(Datamodel): + _name = "pms.account.info" id = fields.Integer(required=False, allow_none=True) amount = fields.Float(required=False, allow_none=True) name = fields.String(required=False, allow_none=True) date = fields.String(required=False, allow_none=True) paymentState = fields.String(required=False, allow_none=True) state = fields.String(required=False, allow_none=True) + # partnerName??, is not enought partnerId? partnerName = fields.String(required=False, allow_none=True) + partnerId = fields.Int(required=False, allow_none=True) moveLines = fields.List(NestedModel("pms.invoice.line.info")) + saleLines = fields.List(NestedModel("pms.folio.sale.line.info")) diff --git a/pms_api_rest/services/__init__.py b/pms_api_rest/services/__init__.py index 2aa929596..f38e8f73d 100644 --- a/pms_api_rest/services/__init__.py +++ b/pms_api_rest/services/__init__.py @@ -37,3 +37,4 @@ from . import pms_room_closure_reason_service from . import res_lang_service from . import pms_account_payment_terms_service from . import pms_account_journal_service +from . import pms_invoice_service diff --git a/pms_api_rest/services/pms_folio_service.py b/pms_api_rest/services/pms_folio_service.py index a46e4c85b..a97d930ae 100644 --- a/pms_api_rest/services/pms_folio_service.py +++ b/pms_api_rest/services/pms_folio_service.py @@ -214,7 +214,7 @@ class PmsFolioService(Component): "POST", ) ], - input_param=Datamodel("pms.account.payment.short.info", is_list=False), + input_param=Datamodel("pms.account.payment.info", is_list=False), auth="jwt_api_pms", ) def create_folio_charge(self, folio_id, pms_account_payment_info): @@ -244,7 +244,7 @@ class PmsFolioService(Component): "POST", ) ], - input_param=Datamodel("pms.account.payment.short.info", is_list=False), + input_param=Datamodel("pms.account.payment.info", is_list=False), auth="jwt_api_pms", ) def create_folio_refund(self, folio_id, pms_account_payment_info): @@ -485,7 +485,7 @@ class PmsFolioService(Component): "GET", ) ], - output_param=Datamodel("pms.account.move.info", is_list=True), + output_param=Datamodel("pms.account.info", is_list=True), auth="jwt_api_pms", ) def get_folio_invoices(self, folio_id): @@ -494,7 +494,7 @@ class PmsFolioService(Component): if not folio: pass else: - PmsFolioInvoiceInfo = self.env.datamodels["pms.account.move.info"] + PmsFolioInvoiceInfo = self.env.datamodels["pms.account.info"] PmsInvoiceLineInfo = self.env.datamodels["pms.invoice.line.info"] if folio.move_ids: for move_id in folio.move_ids: @@ -522,8 +522,8 @@ class PmsFolioService(Component): amount=round(move_id.amount_total, 2) if move_id.amount_total else None, - date=move_id.date.strftime("%d/%m/%Y") - if move_id.date + date=move_id.invoice_date.strftime("%d/%m/%Y") + if move_id.invoice_date else None, state=move_id.state if move_id.state else None, paymentState=move_id.payment_state @@ -536,3 +536,43 @@ class PmsFolioService(Component): ) ) return invoices + + @restapi.method( + [ + ( + [ + "//invoices", + ], + "POST", + ) + ], + input_param=Datamodel("pms.account.info", is_list=False), + auth="jwt_api_pms", + ) + def create_folio_invoices(self, folio_id, invoice_info): + # TODO: Missing payload data: + # - partnerId selected + # - quantity to invoice selected + # - front line description modification + # - data format mal formartted + # - invoice comment + + # date_invoice = fields.Date.from_string(invoice_info.date) + # if not date_invoice: + # raise MissingError(_("Date is required")) + lines_to_invoice_dict = dict() + for item in invoice_info.saleLines: + # TODO: Need get specific to_invoice front value + if item.qtyToInvoice: + lines_to_invoice_dict[item.id] = item.qtyToInvoice + + sale_lines_to_invoice = self.env["folio.sale.line"].browse( + lines_to_invoice_dict.keys() + ) + folios_to_invoice = sale_lines_to_invoice.folio_id + invoices = folios_to_invoice._create_invoices( + # date=date_invoice, TODO: Wrong format date from front + lines_to_invoice=lines_to_invoice_dict, + partner_invoice_id=105165, + ) + return invoices.ids diff --git a/pms_api_rest/services/pms_invoice_service.py b/pms_api_rest/services/pms_invoice_service.py new file mode 100644 index 000000000..8149f11de --- /dev/null +++ b/pms_api_rest/services/pms_invoice_service.py @@ -0,0 +1,105 @@ +from datetime import datetime + +from odoo import _, fields + +from odoo.addons.base_rest import restapi +from odoo.addons.base_rest_datamodel.restapi import Datamodel +from odoo.addons.component.core import Component + + +class PmsInvoiceService(Component): + _inherit = "base.rest.service" + _name = "pms.room.service" + _usage = "invoices" + _collection = "pms.services" + + @restapi.method( + [ + ( + [ + "/p/", + ], + "PATCH", + ) + ], + input_param=Datamodel("pms.invoice.info"), + auth="jwt_api_pms", + ) + def update_invoice(self, invoice_id, pms_invoice_info): + invoice = self.env["account.move"].browse(invoice_id) + company = invoice.company_id + + # Build update values dict + # TODO: Missing data: + # - invoice comment (narration) + # - add new invoice lines (from saleLines selected?) + + new_vals = {} + if ( + pms_invoice_info.partnerId + and pms_invoice_info.partnerId != invoice.partner_id.id + ): + new_vals["partner_id"] = pms_invoice_info.partnerId + + if pms_invoice_info.date: + invoice_date_info = fields.Date.from_string(pms_invoice_info.date) + if invoice_date_info != invoice.invoice_date: + new_vals["invoice_date"] = invoice_date_info + + # If invoice lines are updated, we expect that all lines will be + # 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["reservation_line_ids"] = [] + for line in invoice.invoice_line_ids: + line_info = [ + item.id for item in pms_invoice_info.moveLines if item.id == line.id + ] + if line_info: + 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 + new_vals["reservation_line_ids"].append((1, 4, line_values)) + else: + new_vals["reservation_line_ids"].append((2, line.id)) + + if not new_vals: + return invoice.id + + # 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. + if invoice.state != "draft" and company.corrective_invoice_policy == "strict": + # 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() + datetime.timedelta(days=7), + "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) + return invoice.id + + def _direct_move_update(self, invoice, new_vals): + previus_state = invoice.state + if previus_state == "posted": + invoice.button_draft() + if new_vals: + invoice.write(new_vals) + if previus_state == "posted": + invoice.action_post() + return invoice diff --git a/pms_api_rest/services/pms_partner_service.py b/pms_api_rest/services/pms_partner_service.py index 8ce5c7955..f75c60a73 100644 --- a/pms_api_rest/services/pms_partner_service.py +++ b/pms_api_rest/services/pms_partner_service.py @@ -246,7 +246,7 @@ class PmsPartnerService(Component): "GET", ) ], - output_param=Datamodel("pms.account.move.info", is_list=True), + output_param=Datamodel("pms.account.info", is_list=True), auth="jwt_api_pms", ) def get_partner_invoices(self, partner_id): @@ -256,7 +256,7 @@ class PmsPartnerService(Component): ("move_type", "in", self.env["account.move"].get_invoice_types()), ] ) - PmsAcoountMoveInfo = self.env.datamodels["pms.account.move.info"] + PmsAcoountMoveInfo = self.env.datamodels["pms.account.info"] invoices = [] for invoice in partnerInvoices: invoices.append(