mirror of
https://gitlab.com/flectra-community/l10n-switzerland-flectra.git
synced 2024-12-24 13:21:46 +00:00
182 lines
6.5 KiB
Python
182 lines
6.5 KiB
Python
# Copyright 2019 Camptocamp SA
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
|
|
|
import os
|
|
from datetime import datetime
|
|
|
|
# Needs Jinja 2.10
|
|
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
|
|
|
from flectra import fields, models
|
|
from flectra.modules.module import get_module_root
|
|
|
|
from flectra.addons.base.models.res_bank import sanitize_account_number
|
|
|
|
from ..components.api import PayNetDWS
|
|
|
|
import zeep # isort:skip
|
|
|
|
|
|
MODULE_PATH = get_module_root(os.path.dirname(__file__))
|
|
INVOICE_TEMPLATE_2013 = "invoice-2013A.xml"
|
|
INVOICE_TEMPLATE_2003 = "invoice-2003A.xml"
|
|
TEMPLATE_DIR = [MODULE_PATH + "/messages"]
|
|
|
|
DOCUMENT_TYPE = {"out_invoice": "EFD", "out_refund": "EGS"}
|
|
|
|
|
|
class PaynetInvoiceMessage(models.Model):
|
|
_name = "paynet.invoice.message"
|
|
_description = "Paynet shipment send to service"
|
|
|
|
service_id = fields.Many2one(
|
|
comodel_name="paynet.service",
|
|
string="Paynet Service",
|
|
required=True,
|
|
ondelete="restrict",
|
|
readonly=True,
|
|
)
|
|
invoice_id = fields.Many2one(comodel_name="account.move", ondelete="restrict")
|
|
attachment_id = fields.Many2one("ir.attachment", "PDF")
|
|
state = fields.Selection(
|
|
selection=[
|
|
("draft", "Draft"),
|
|
("sent", "Sent"),
|
|
("done", "Done"),
|
|
("reject", "Reject"),
|
|
("error", "Error"),
|
|
],
|
|
default="draft",
|
|
)
|
|
ic_ref = fields.Char(
|
|
string="IC Ref", size=14, help="Document interchange reference"
|
|
)
|
|
# Set with invoice_id.number but also with returned data from server ?
|
|
ref = fields.Char("Reference No.", size=35)
|
|
ebill_account_number = fields.Char("Paynet Id", size=20)
|
|
payload = fields.Text("Payload sent")
|
|
response = fields.Text("Response recieved")
|
|
shipment_id = fields.Char(size=24, help="Shipment Id on Paynet service")
|
|
payment_type = fields.Selection(
|
|
selection=[("qr", "QR"), ("esr", "ESR"), ("esp", "ESP"), ("npy", "NPY")],
|
|
default="qr",
|
|
readonly=True,
|
|
)
|
|
|
|
def _get_ic_ref(self):
|
|
return "SA%012d" % self.id
|
|
|
|
def send_to_paynet(self):
|
|
for message in self:
|
|
message.payload = message._generate_payload()
|
|
try:
|
|
shipment_id = message.service_id.take_shipment(message.payload)
|
|
message.shipment_id = shipment_id
|
|
message.state = "sent"
|
|
except zeep.exceptions.Fault as e:
|
|
message.response = PayNetDWS.handle_fault(e)
|
|
message.state = "error"
|
|
|
|
@staticmethod
|
|
def format_date(date_string=None):
|
|
if not date_string:
|
|
date_string = datetime.now()
|
|
return date_string.strftime("%Y%m%d")
|
|
|
|
def _get_payload_params(self):
|
|
self.ic_ref = self._get_ic_ref()
|
|
bank_account = ""
|
|
if self.payment_type == "qr":
|
|
bank_account = sanitize_account_number(
|
|
self.invoice_id.partner_bank_id.l10n_ch_qr_iban
|
|
or self.invoice_id.partner_bank_id.acc_number
|
|
)
|
|
else:
|
|
bank_account = self.invoice_id.partner_bank_id.l10n_ch_isr_subscription_chf
|
|
if bank_account:
|
|
account_parts = bank_account.split("-")
|
|
bank_account = (
|
|
account_parts[0] + account_parts[1].rjust(6, "0") + account_parts[2]
|
|
)
|
|
else:
|
|
bank_account = ""
|
|
|
|
params = {
|
|
"client_pid": self.service_id.client_pid,
|
|
"invoice": self.invoice_id,
|
|
"invoice_lines": self.invoice_id.paynet_invoice_line_ids(),
|
|
"biller": self.invoice_id.company_id,
|
|
"customer": self.invoice_id.partner_id,
|
|
"delivery": self.invoice_id.partner_shipping_id,
|
|
"pdf_data": self.attachment_id.datas.decode("ascii"),
|
|
"bank": self.invoice_id.partner_bank_id,
|
|
"bank_account": bank_account,
|
|
"ic_ref": self.ic_ref,
|
|
"payment_type": self.payment_type,
|
|
"document_type": DOCUMENT_TYPE[self.invoice_id.move_type],
|
|
"format_date": self.format_date,
|
|
"ebill_account_number": self.ebill_account_number,
|
|
"discount_template": "",
|
|
"discount": {},
|
|
}
|
|
amount_by_group = []
|
|
# Get the percentage of the tax from the name of the group
|
|
# Could be improve by searching in the account_tax linked to the group
|
|
for taxgroup in self.invoice_id.amount_by_group:
|
|
rate = taxgroup[0].split()[-1:][0][:-1]
|
|
amount_by_group.append(
|
|
(
|
|
rate or "0",
|
|
taxgroup[1],
|
|
taxgroup[2],
|
|
)
|
|
)
|
|
params["amount_by_group"] = amount_by_group
|
|
# Get the invoice due date
|
|
date_due = None
|
|
if self.invoice_id.invoice_payment_term_id:
|
|
terms = self.invoice_id.invoice_payment_term_id.compute(
|
|
self.invoice_id.amount_total
|
|
)
|
|
if terms:
|
|
# Returns all payment and their date like [('2020-12-07', 430.37), ...]
|
|
# Get the last payment date in the format "202021207"
|
|
date_due = terms[-1][0].replace("-", "")
|
|
if not date_due:
|
|
date_due = self.format_date(
|
|
self.invoice_id.invoice_date_due or self.invoice_id.invoice_date
|
|
)
|
|
params["date_due"] = date_due
|
|
return params
|
|
|
|
def _get_jinja_env(self, template_dir):
|
|
jinja_env = Environment(
|
|
loader=FileSystemLoader(template_dir),
|
|
autoescape=select_autoescape(["xml"]),
|
|
)
|
|
# Force the truncate filter to be exact
|
|
jinja_env.policies["truncate.leeway"] = 0
|
|
return jinja_env
|
|
|
|
def _get_template(self, jinja_env):
|
|
if self.service_id.service_type == "b2b":
|
|
return jinja_env.get_template(INVOICE_TEMPLATE_2003)
|
|
else:
|
|
return jinja_env.get_template(INVOICE_TEMPLATE_2013)
|
|
|
|
def _generate_payload(self):
|
|
self.ensure_one()
|
|
assert self.state == "draft"
|
|
params = self._get_payload_params()
|
|
jinja_env = self._get_jinja_env(TEMPLATE_DIR)
|
|
jinja_template = self._get_template(jinja_env)
|
|
return jinja_template.render(params)
|
|
|
|
def update_invoice_status(self):
|
|
"""Update the export status in the chatter."""
|
|
for message in self:
|
|
if message.state == "done":
|
|
message.invoice_id.log_invoice_accepted_by_system()
|
|
elif message.state in ["reject", "error"]:
|
|
message.invoice_id.log_invoice_refused_by_system()
|