summaryrefslogtreecommitdiff
path: root/addons/l10n_id_efaktur/models/efaktur.py
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/l10n_id_efaktur/models/efaktur.py
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/l10n_id_efaktur/models/efaktur.py')
-rw-r--r--addons/l10n_id_efaktur/models/efaktur.py109
1 files changed, 109 insertions, 0 deletions
diff --git a/addons/l10n_id_efaktur/models/efaktur.py b/addons/l10n_id_efaktur/models/efaktur.py
new file mode 100644
index 00000000..b54c8382
--- /dev/null
+++ b/addons/l10n_id_efaktur/models/efaktur.py
@@ -0,0 +1,109 @@
+# -*- encoding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models, _
+from odoo.exceptions import ValidationError
+
+import re
+
+
+class Efaktur(models.Model):
+ _name = "l10n_id_efaktur.efaktur.range"
+ _description = "Available E-faktur range"
+
+ company_id = fields.Many2one('res.company', required=True, default=lambda self: self.env.company)
+ max = fields.Char(compute='_compute_default', store=True, readonly=False)
+ min = fields.Char(compute='_compute_default', store=True, readonly=False)
+ available = fields.Integer(compute='_compute_available', store=True)
+
+ @api.model
+ def pop_number(self, company_id):
+ range = self.search([('company_id', '=', company_id)], order="min ASC", limit=1)
+ if not range:
+ return None
+
+ popped = int(range.min)
+ if int(range.min) >= int(range.max):
+ range.unlink()
+ else:
+ range.min = '%013d' % (popped + 1)
+ return popped
+
+ @api.model
+ def push_number(self, company_id, number):
+ return self.push_numbers(company_id, number, number)
+
+ @api.model
+ def push_numbers(self, company_id, min, max):
+ range_sup = self.search([('min', '=', '%013d' % (int(max) + 1))])
+ if range_sup:
+ range_sup.min = '%013d' % int(min)
+ max = range_sup.max
+
+ range_low = self.search([('max', '=', '%013d' % (int(max) - 1))])
+ if range_low:
+ range_sup.unlink()
+ range_low.max = '%013d' % int(max)
+
+ if not range_sup and not range_low:
+ self.create({
+ 'company_id': company_id,
+ 'max': '%013d' % int(max),
+ 'min': '%013d' % int(min),
+ })
+
+
+ @api.constrains('min', 'max')
+ def _constrains_min_max(self):
+ for record in self:
+ if not len(record.min) == 13 or not len(record.max) == 13:
+ raise ValidationError(_("There should be 13 digits in each number."))
+
+ if record.min[:-8] != record.max[:-8]:
+ raise ValidationError(_("First 5 digits should be same in Start Number and End Number."))
+
+ if int(record.min[-8:]) > int(record.max[-8:]):
+ raise ValidationError(_("Last 8 digits of End Number should be greater than the last 8 digit of Start Number"))
+
+ if (int(record.max) - int(record.min)) > 10000:
+ raise ValidationError(_("The difference between the two numbers must not be greater than 10.000"))
+
+ # The number of records should always be very small, so it is ok to search in loop
+ if self.search([
+ '&', ('id', '!=', record.id), '|', '|',
+ '&', ('min', '<=', record.max), ('max', '>=', record.max),
+ '&', ('min', '<=', record.min), ('max', '>=', record.min),
+ '&', ('min', '>=', record.min), ('max', '<=', record.max),
+ ]):
+ raise ValidationError(_('Efaktur interleaving range detected'))
+
+ @api.depends('min', 'max')
+ def _compute_available(self):
+ for record in self:
+ record.available = 1 + int(record.max) - int(record.min)
+
+ @api.depends('company_id')
+ def _compute_default(self):
+ for record in self:
+ query = """
+ SELECT MAX(SUBSTRING(l10n_id_tax_number FROM 4))
+ FROM account_move
+ WHERE l10n_id_tax_number IS NOT NULL
+ AND company_id = %s
+ """
+ self.env.cr.execute(query, [record.company_id.id])
+ max_used = int(self.env.cr.fetchone()[0] or 0)
+ max_available = int(self.env['l10n_id_efaktur.efaktur.range'].search([('company_id', '=', record.company_id.id)], order='max DESC', limit=1).max)
+ record.min = record.max = '%013d' % (max(max_available, max_used) + 1)
+
+ @api.onchange('min')
+ def _onchange_min(self):
+ self.min = '%013d' % int(re.sub(r'\D', '', self.min))
+ if not self.max or int(self.min) > int(self.max):
+ self.max = self.min
+
+ @api.onchange('max')
+ def _onchange_max(self):
+ self.max = '%013d' % int(re.sub(r'\D', '', self.max))
+ if not self.min or int(self.min) > int(self.max):
+ self.min = self.max