Initial import from ash-technology/l10n_cz_extra
Czech QR Payment (SPAYD) module for Odoo 19 - Generates Czech standard QR codes for invoices - Compatible with all major Czech banking apps Cloned from: https://github.com/ash-technology/l10n_cz_extra Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
Executable
+1
@@ -0,0 +1 @@
|
||||
from . import account_move
|
||||
@@ -0,0 +1,76 @@
|
||||
import qrcode
|
||||
import base64
|
||||
import io
|
||||
from odoo import models, api
|
||||
|
||||
class AccountMove(models.Model):
|
||||
_inherit = 'account.move'
|
||||
|
||||
def get_cz_qr_code_base64(self):
|
||||
""" Returns Base64 PNG image for the invoice PDF """
|
||||
self.ensure_one()
|
||||
if self.currency_id.name != 'CZK':
|
||||
return False
|
||||
|
||||
# Find bank: 1. Matching CZK, 2. No currency set (default)
|
||||
bank = self.company_id.partner_id.bank_ids.filtered(lambda b: b.currency_id == self.currency_id)[:1]
|
||||
if not bank:
|
||||
bank = self.company_id.partner_id.bank_ids.filtered(lambda b: not b.currency_id)[:1]
|
||||
|
||||
if not bank or not bank.acc_number:
|
||||
return False
|
||||
|
||||
# Build SPAYD string
|
||||
iban = self.cz_to_iban(bank.acc_number)
|
||||
amount = '%.2f' % self.amount_residual
|
||||
vs = ''.join(filter(str.isdigit, self.payment_reference or ''))[-10:]
|
||||
|
||||
spayd = f"SPD*1.0*ACC:{iban}*AM:{amount}*CC:CZK*X-VS:{vs}"
|
||||
|
||||
# Generate QR Image
|
||||
qr = qrcode.make(spayd)
|
||||
buf = io.BytesIO()
|
||||
qr.save(buf, format="PNG")
|
||||
return base64.b64encode(buf.getvalue()).decode('utf-8')
|
||||
|
||||
def cz_to_iban(self, acc_number):
|
||||
"""
|
||||
Converts '123-456/0800' or '456/0800' to a valid CZ IBAN.
|
||||
"""
|
||||
if not acc_number:
|
||||
return ""
|
||||
|
||||
# Clean the input
|
||||
clean_acc = acc_number.replace(" ", "")
|
||||
|
||||
# If already an IBAN, return it
|
||||
if clean_acc.upper().startswith('CZ'):
|
||||
return clean_acc.upper()
|
||||
|
||||
try:
|
||||
# Split into [prefix-main, bank_code]
|
||||
parts = clean_acc.split('/')
|
||||
if len(parts) != 2:
|
||||
return clean_acc # Fallback
|
||||
|
||||
bank_code = parts[1]
|
||||
account_parts = parts[0].split('-')
|
||||
|
||||
if len(account_parts) == 2:
|
||||
prefix = account_parts[0].zfill(6)
|
||||
main = account_parts[1].zfill(10)
|
||||
else:
|
||||
prefix = "000000"
|
||||
main = account_parts[0].zfill(10)
|
||||
|
||||
# 1. Start with Bank Code + Prefix + Main + Country Number (CZ=12, 35=Z) + 00
|
||||
# Czech Republic code is 123500 (12 for C, 35 for Z)
|
||||
check_string = f"{bank_code}{prefix}{main}123500"
|
||||
|
||||
# 2. Calculate checksum
|
||||
checksum = 98 - (int(check_string) % 97)
|
||||
checksum_str = str(checksum).zfill(2)
|
||||
|
||||
return f"CZ{checksum_str}{bank_code}{prefix}{main}"
|
||||
except Exception:
|
||||
return clean_acc
|
||||
Reference in New Issue
Block a user