
модуль l10n_ru_contract файл /l10n_ru_contract/views/contract_customer_view.xml Были изменены id в menuitem с contract на l10n_ru_contract 10n_ru_doc/demo/l10n_ru_doc_demo.xml Закомментированно поле <field name="rml_header1">CodUP</field> ( его в 17-ой версии я не нашел, аналог тоже) Модуль l10n_ru_doc l10n_ru_doc/demo/l10n_ru_doc_demo.xml Заменено поле image на image_1920 Что добавить в Rudo для работы модулей l10n_ru Список штатных модулей: account account_payment payment payment_adyen payment_alipay payment_aps payment_authorize payment_buckaroo payment_custom payment_demo payment_flutterwave payment_mercado_pago payment_mollie payment_ogone payment_paypal payment_payumoney payment_razorpay payment_razorpay_oauth payment_sips payment_stripe payment_xendit payment_asiapay payment_payulatam product purchase sale sale_management stock utm Так же в odoo/tools нужно добавить папку pdf из базового ядра odoo17 в odoo/addons нужно добавить модуль test_mimetypes в файле payment/data/payment_provider_data.xml нужно закомментировать запись payment_provider_sepa_direct_debit В виртуальную среду добавить библиотеку pymorphy2
354 lines
12 KiB
Python
Executable File
354 lines
12 KiB
Python
Executable File
from odoo import api, fields, models, exceptions
|
||
from datetime import datetime
|
||
import re
|
||
import pymorphy2
|
||
from odoo.tools import pycompat
|
||
|
||
FRACTIONS = (
|
||
(u"десятая", u"десятых", u"десятых"),
|
||
(u"сотая", u"сотых", u"сотых"),
|
||
(u"тысячная", u"тысячных", u"тысячных"),
|
||
(u"десятитысячная", u"десятитысячных", u"десятитысячных"),
|
||
(u"стотысячная", u"стотысячных", u"стотысячных"),
|
||
(u"миллионная", u"милллионных", u"милллионных"),
|
||
(u"десятимиллионная", u"десятимилллионных", u"десятимиллионных"),
|
||
(u"стомиллионная", u"стомилллионных", u"стомиллионных"),
|
||
(u"миллиардная", u"миллиардных", u"миллиардных"),
|
||
)
|
||
|
||
ONES = {
|
||
0: (u"", u"", u""),
|
||
1: (u"один", u"одна", u"одно"),
|
||
2: (u"два", u"две", u"два"),
|
||
3: (u"три", u"три", u"три"),
|
||
4: (u"четыре", u"четыре", u"четыре"),
|
||
5: (u"пять", u"пять", u"пять"),
|
||
6: (u"шесть", u"шесть", u"шесть"),
|
||
7: (u"семь", u"семь", u"семь"),
|
||
8: (u"восемь", u"восемь", u"восемь"),
|
||
9: (u"девять", u"девять", u"девять"),
|
||
}
|
||
|
||
TENS = {
|
||
0: u"",
|
||
10: u"десять",
|
||
11: u"одиннадцать",
|
||
12: u"двенадцать",
|
||
13: u"тринадцать",
|
||
14: u"четырнадцать",
|
||
15: u"пятнадцать",
|
||
16: u"шестнадцать",
|
||
17: u"семнадцать",
|
||
18: u"восемнадцать",
|
||
19: u"девятнадцать",
|
||
2: u"двадцать",
|
||
3: u"тридцать",
|
||
4: u"сорок",
|
||
5: u"пятьдесят",
|
||
6: u"шестьдесят",
|
||
7: u"семьдесят",
|
||
8: u"восемьдесят",
|
||
9: u"девяносто",
|
||
}
|
||
|
||
HUNDREDS = {
|
||
0: u"",
|
||
1: u"сто",
|
||
2: u"двести",
|
||
3: u"триста",
|
||
4: u"четыреста",
|
||
5: u"пятьсот",
|
||
6: u"шестьсот",
|
||
7: u"семьсот",
|
||
8: u"восемьсот",
|
||
9: u"девятьсот",
|
||
}
|
||
|
||
MALE = 1
|
||
FEMALE = 2
|
||
|
||
import operator
|
||
import sys
|
||
import types
|
||
|
||
PY2 = sys.version_info[0] == 2
|
||
PY3 = sys.version_info[0] == 3
|
||
|
||
if PY3:
|
||
string_types = str,
|
||
integer_types = int,
|
||
class_types = type,
|
||
text_type = str
|
||
binary_type = bytes
|
||
|
||
MAXSIZE = sys.maxsize
|
||
else:
|
||
string_types = basestring,
|
||
integer_types = (int, long)
|
||
class_types = (type, types.ClassType)
|
||
text_type = unicode
|
||
binary_type = str
|
||
|
||
|
||
class Partner_Bank(models.Model):
|
||
_inherit = 'res.partner.bank'
|
||
bank_corr_acc = fields.Char('Кор.счет')
|
||
|
||
|
||
# class Bank(models.Model):
|
||
# _inherit = 'res.bank'
|
||
|
||
# corr_acc = fields.Char('Corresponding account', size=64)
|
||
|
||
# class Users(models.Model):
|
||
# _inherit = 'res.users'
|
||
|
||
# facsimile = fields.Binary("Facsimile")
|
||
|
||
class Company(models.Model):
|
||
_inherit = 'res.company'
|
||
|
||
inn = fields.Char(related='partner_id.inn', readonly=False)
|
||
kpp = fields.Char(related='partner_id.kpp', readonly=False)
|
||
okpo = fields.Char(related='partner_id.okpo', readonly=False)
|
||
chief_id = fields.Many2one('res.users', 'Имя директора')
|
||
stamp = fields.Binary("Stamp")
|
||
|
||
|
||
class Partner(models.Model):
|
||
_inherit = 'res.partner'
|
||
ogrn = fields.Char('ОГРН')
|
||
okpo = fields.Char('ОКПО')
|
||
inn = fields.Char('ИНН')
|
||
kpp = fields.Char('KPP')
|
||
passport = fields.Char('Паспорт')
|
||
|
||
|
||
class Report_contract_customer(models.Model):
|
||
_inherit = 'partner.contract.customer'
|
||
|
||
def img(self, img, type='png', width=0, height=0):
|
||
if width:
|
||
width = "width='%spx'" % (width)
|
||
else:
|
||
width = " "
|
||
if height:
|
||
height = "height='%spx'" % (height)
|
||
else:
|
||
height = " "
|
||
toreturn = "<img %s %s src='data:image/%s;base64,%s' />" % (
|
||
width,
|
||
height,
|
||
type,
|
||
str(pycompat.to_text(img)))
|
||
return toreturn
|
||
|
||
def numer(self, name):
|
||
if name:
|
||
numeration = re.findall('\d+$', name)
|
||
if numeration: return numeration[0]
|
||
return ''
|
||
|
||
def ru_date(self, date):
|
||
if date and date != 'False':
|
||
return dt.ru_strftime(u'"%d" %B %Y года', date=datetime.strptime(str(date), "%Y-%m-%d"), inflected=True)
|
||
return ''
|
||
|
||
def ru_date2(self, date):
|
||
if date and date != 'False':
|
||
return dt.ru_strftime(u'%d %B %Y г.', date=datetime.strptime(str(date), "%Y-%m-%d %H:%M:%S"),
|
||
inflected=True)
|
||
return ''
|
||
|
||
def in_words(self, number):
|
||
return numeral.in_words(number)
|
||
|
||
def rubles(self, sum):
|
||
"Transform sum number in rubles to text"
|
||
text_rubles = self.numeral_rubles(int(sum))
|
||
copeck = round((sum - int(sum)) * 100)
|
||
text_copeck = self.numeral_choose_plural(int(copeck), (u"копейка", u"копейки", u"копеек"))
|
||
return ("%s %02d %s") % (text_rubles, copeck, text_copeck)
|
||
|
||
def numeral_rubles(self, amount, zero_for_kopeck=False):
|
||
self.check_positive(amount)
|
||
pts = []
|
||
amount = round(amount, 2)
|
||
pts.append(self.sum_string(int(amount), 1, (u"рубль", u"рубля", u"рублей")))
|
||
remainder = self._get_float_remainder(amount, 2)
|
||
iremainder = int(remainder)
|
||
|
||
if iremainder != 0 or zero_for_kopeck:
|
||
if iremainder < 10 and len(remainder) == 1:
|
||
iremainder *= 10
|
||
pts.append(self.sum_string(iremainder, 2,
|
||
(u"копейка", u"копейки", u"копеек")))
|
||
return u" ".join(pts)
|
||
|
||
def _get_float_remainder(self, fvalue, signs=9):
|
||
self.check_positive(fvalue)
|
||
if isinstance(fvalue, integer_types):
|
||
return "0"
|
||
if isinstance(fvalue, Decimal) and fvalue.as_tuple()[2] == 0:
|
||
return "0"
|
||
|
||
def sum_string(self, amount, gender, items=None):
|
||
if isinstance(items, text_type):
|
||
items = split_values(items)
|
||
if items is None:
|
||
items = (u"", u"", u"")
|
||
try:
|
||
one_item, two_items, five_items = items
|
||
except ValueError:
|
||
raise ValueError("Items must be 3-element sequence")
|
||
self.check_positive(amount)
|
||
if amount == 0:
|
||
return u"ноль %s" % five_items
|
||
into = u''
|
||
tmp_val = amount
|
||
into, tmp_val = self._sum_string_fn(into, tmp_val, gender, items)
|
||
into, tmp_val = self._sum_string_fn(into, tmp_val, FEMALE,
|
||
(u"тысяча", u"тысячи", u"тысяч"))
|
||
into, tmp_val = self._sum_string_fn(into, tmp_val, MALE,
|
||
(u"миллион", u"миллиона", u"миллионов"))
|
||
into, tmp_val = self._sum_string_fn(into, tmp_val, MALE,
|
||
(u"миллиард", u"миллиарда", u"миллиардов"))
|
||
if tmp_val == 0:
|
||
return into
|
||
else:
|
||
raise ValueError("Cannot operand with numbers bigger than 10**11")
|
||
|
||
def _sum_string_fn(self, into, tmp_val, gender, items=None):
|
||
if items is None:
|
||
items = (u"", u"", u"")
|
||
one_item, two_items, five_items = items
|
||
self.check_positive(tmp_val)
|
||
if tmp_val == 0:
|
||
return into, tmp_val
|
||
words = []
|
||
rest = tmp_val % 1000
|
||
tmp_val = tmp_val // 1000
|
||
if rest == 0:
|
||
if into == u"":
|
||
into = u"%s " % five_items
|
||
return into, tmp_val
|
||
end_word = five_items
|
||
words.append(HUNDREDS[rest // 100])
|
||
rest = rest % 100
|
||
rest1 = rest // 10
|
||
tens = rest1 == 1 and TENS[rest] or TENS[rest1]
|
||
words.append(tens)
|
||
if rest1 < 1 or rest1 > 1:
|
||
amount = rest % 10
|
||
end_word = self.numeral_choose_plural(amount, items)
|
||
words.append(ONES[amount][gender - 1])
|
||
words.append(end_word)
|
||
words.append(into)
|
||
words = filter(lambda x: len(x) > 0, words)
|
||
return u" ".join(words).strip(), tmp_val
|
||
|
||
def check_positive(self, value, strict=False):
|
||
if not strict and value < 0:
|
||
raise ValueError("Value must be positive or zero, not %s" % str(value))
|
||
if strict and value <= 0:
|
||
raise ValueError("Value must be positive, not %s" % str(value))
|
||
|
||
def numeral_choose_plural(self, amount, variants):
|
||
if isinstance(variants, text_type):
|
||
variants = split_values(variants)
|
||
self.check_length(variants, 3)
|
||
amount = abs(amount)
|
||
if amount % 10 == 1 and amount % 100 != 11:
|
||
variant = 0
|
||
elif amount % 10 >= 2 and amount % 10 <= 4 and \
|
||
(amount % 100 < 10 or amount % 100 >= 20):
|
||
variant = 1
|
||
else:
|
||
variant = 2
|
||
return variants[variant]
|
||
|
||
def check_length(self, value, length):
|
||
_length = len(value)
|
||
if _length != length:
|
||
raise ValueError("length must be %d, not %d" % \
|
||
(length, _length))
|
||
|
||
def initials(self, fio):
|
||
if fio:
|
||
return (fio.split()[0] + ' ' + ''.join([fio[0:1] + '.' for fio in fio.split()[1:]])).strip()
|
||
return ''
|
||
|
||
def address(self, partner):
|
||
repr = []
|
||
if partner.zip: repr.append(partner.zip)
|
||
if partner.city: repr.append(partner.city)
|
||
if partner.street: repr.append(partner.street)
|
||
if partner.street2: repr.append(partner.street2)
|
||
return ', '.join(repr)
|
||
|
||
def address_delivery(self, partner):
|
||
if partner:
|
||
addr = self.env['res.partner'].search([('parent_id', '=', partner), ('type', '=', 'delivery')], limit=1)
|
||
repr = []
|
||
if addr:
|
||
if addr.zip: repr.append(addr.zip)
|
||
if addr.city: repr.append(addr.city)
|
||
if addr.street: repr.append(addr.street)
|
||
if addr.street2: repr.append(addr.street2)
|
||
return ', '.join(repr)
|
||
|
||
def get_function_print(self, function):
|
||
morph = pymorphy2.MorphAnalyzer()
|
||
if function:
|
||
f = morph.parse(function)[0]
|
||
f = f.inflect({'gent'}).word
|
||
return f.title()
|
||
|
||
def get_function_partnerip(self, partner):
|
||
director = self.env['res.partner'].search([('parent_id', '=', partner), ('type', '=', 'director')], limit=1)
|
||
if director:
|
||
if director.function:
|
||
return director.function
|
||
|
||
def get_function_partner(self, partner):
|
||
res = []
|
||
morph = pymorphy2.MorphAnalyzer()
|
||
if partner:
|
||
director = self.env['res.partner'].search([('parent_id', '=', partner), ('type', '=', 'director')], limit=1)
|
||
if director:
|
||
if director.function:
|
||
list_f = str(director.function).split(' ')
|
||
for func in list_f:
|
||
f = morph.parse(func)[0]
|
||
f = f.inflect({'gent'}).word
|
||
res.append(f)
|
||
return ' '.join(res)
|
||
|
||
def get_function_partner1(self, partner):
|
||
if partner:
|
||
director = self.env['res.partner'].search([('parent_id', '=', partner), ('type', '=', 'director')], limit=1)
|
||
if director:
|
||
if director.function:
|
||
return director.function
|
||
|
||
def get_date_text(self, date):
|
||
month_list = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября',
|
||
'ноября', 'декабря']
|
||
if date:
|
||
date_list = str(date).split('-')
|
||
if date_list[0] and date_list[1] and date_list[2]:
|
||
return ('"' + date_list[2] + '" ' + month_list[int(date_list[1]) - 1] + ' ' + date_list[0] + ' г.')
|
||
|
||
def get_bank(self, partner):
|
||
repr = []
|
||
bank = None
|
||
if partner.bank_ids:
|
||
bank = partner.bank_ids[0]
|
||
elif partner.parent_id.bank_ids:
|
||
bank = partner.parent_id.bank_ids[0]
|
||
if bank and bank.bank_name: repr.append(bank.bank_name)
|
||
if bank and bank.acc_number: repr.append(u"Р/счет " + bank.acc_number)
|
||
if bank and bank.bank_bic: repr.append(u"БИК " + bank.bank_bic)
|
||
if bank and bank.bank_corr_acc: repr.append(u"к/с " + bank.bank_corr_acc)
|
||
return '<br/>'.join(repr)
|