Merge branch 'staging' into 'development'
Staging See merge request tabulasense/client_contracts!9
This commit is contained in:
commit
deade69594
11
TODOLIST.md
Normal file
11
TODOLIST.md
Normal file
@ -0,0 +1,11 @@
|
||||
# TODO LIST
|
||||
|
||||
## Features
|
||||
|
||||
## Fixes
|
||||
- Change all `parents` to `genitive`
|
||||
- Merge `document_type` and `template_type` in `res.partner.document.template`
|
||||
- Change `annex_number` to `annex_counter`
|
||||
|
||||
## Big feature
|
||||
- Separate XML actions that generates transient fields for all types of documents
|
@ -19,6 +19,7 @@
|
||||
"security/ir.model.access.csv",
|
||||
"views/res_partner_contract.xml",
|
||||
"views/res_partner_contract_annex.xml",
|
||||
"views/res_partner_contract_field.xml",
|
||||
"views/res_partner_document_template.xml",
|
||||
"views/res_partner.xml",
|
||||
"views/sale_order.xml",
|
||||
|
@ -155,8 +155,8 @@ action = ctx
|
||||
# Aliases
|
||||
self = record
|
||||
|
||||
seller = self.contract_id.company_id
|
||||
partner = self.contract_id.partner_id
|
||||
seller = self.company_id
|
||||
partner = self.partner_id
|
||||
|
||||
seller_bank = seller.bank_ids and seller.bank_ids[0]
|
||||
seller_bank_name = seller_bank.bank_id.name + (" г. {city}".format(city=seller_bank.bank_id.city) if seller_bank.bank_id.city else "")
|
||||
@ -191,7 +191,7 @@ ctx = {
|
||||
"contract_number": self.contract_id.name,
|
||||
|
||||
"annex_name": self.name,
|
||||
"annex_number": self.number,
|
||||
"annex_number": self.counter,
|
||||
|
||||
"order_name": self.order_id.name,
|
||||
"order_date": "{} {} {}".format(order_date.day, months[order_date.month], order_date.year),
|
||||
|
55
i18n/ru.po
55
i18n/ru.po
@ -6,8 +6,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 11.0-20191106\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-01-21 14:27+0000\n"
|
||||
"PO-Revision-Date: 2020-01-21 14:27+0000\n"
|
||||
"POT-Creation-Date: 2020-01-22 11:29+0000\n"
|
||||
"PO-Revision-Date: 2020-01-22 11:29+0000\n"
|
||||
"Last-Translator: Stepan Savelyev\n"
|
||||
"Language-Team: RYDLAB\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -42,14 +42,14 @@ msgid "3 stages"
|
||||
msgstr "Оплата в 3 этапа"
|
||||
|
||||
#. module: client_contracts
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:28
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:31
|
||||
#: selection:res.partner.document.template,document_type_name:0
|
||||
#, python-format
|
||||
msgid "Act of Acceptance and Delivery"
|
||||
msgstr "Акт сдачи-приемки"
|
||||
|
||||
#. module: client_contracts
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:27
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:30
|
||||
#: selection:res.partner.document.template,document_type_name:0
|
||||
#, python-format
|
||||
msgid "Act of Acceptance and Transfer"
|
||||
@ -62,7 +62,7 @@ msgid "Actual Address"
|
||||
msgstr "Актуальный адрес"
|
||||
|
||||
#. module: client_contracts
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:18
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:21
|
||||
#: selection:res.partner.document.template,document_type:0
|
||||
#, python-format
|
||||
msgid "Addition"
|
||||
@ -79,7 +79,7 @@ msgid "Amount Whole Part"
|
||||
msgstr "Целая часть суммы"
|
||||
|
||||
#. module: client_contracts
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:17
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:20
|
||||
#: selection:res.partner.document.template,document_type:0
|
||||
#: selection:res.partner.document.template,template_type:0
|
||||
#, python-format
|
||||
@ -112,7 +112,7 @@ msgid "Annexes to this contract"
|
||||
msgstr "Приложения к договору"
|
||||
|
||||
#. module: client_contracts
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:26
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:29
|
||||
#: selection:res.partner.document.template,document_type_name:0
|
||||
#, python-format
|
||||
msgid "Approval List"
|
||||
@ -147,7 +147,7 @@ msgid "Bank Payment Account"
|
||||
msgstr "Расчётный счёт"
|
||||
|
||||
#. module: client_contracts
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:24
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:27
|
||||
#: selection:res.partner.document.template,document_type_name:0
|
||||
#, python-format
|
||||
msgid "Bill"
|
||||
@ -175,6 +175,7 @@ msgid "Closed"
|
||||
msgstr "Закрыт"
|
||||
|
||||
#. module: client_contracts
|
||||
#: model:ir.model.fields,field_description:client_contracts.field_res_partner_contract_annex_company_id
|
||||
#: model:ir.model.fields,field_description:client_contracts.field_res_partner_contract_company_id
|
||||
#: model:ir.model.fields,field_description:client_contracts.field_res_partner_contract_wizard_company_id
|
||||
msgid "Company"
|
||||
@ -196,7 +197,7 @@ msgid "Contact"
|
||||
msgstr "Контакт"
|
||||
|
||||
#. module: client_contracts
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:16
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:19
|
||||
#: model:ir.model,name:client_contracts.model_res_partner_contract
|
||||
#: model:ir.model.fields,field_description:client_contracts.field_res_partner_contract_annex_contract_id
|
||||
#: model:ir.model.fields,field_description:client_contracts.field_res_partner_contract_field_transient__contract_wizard_id
|
||||
@ -233,6 +234,7 @@ msgid "Contract Field Transient"
|
||||
msgstr "Фактическое поле договора"
|
||||
|
||||
#. module: client_contracts
|
||||
#: model:ir.actions.act_window,name:client_contracts.res_partner_contract_field_action
|
||||
#: model:ir.model.fields,field_description:client_contracts.field_res_partner_contract_wizard_transient_field_ids
|
||||
msgid "Contract Fields"
|
||||
msgstr "Поля договора"
|
||||
@ -269,7 +271,7 @@ msgid "Counter for generate Annex name"
|
||||
msgstr "Счётчик для генерации имени приложения к договору"
|
||||
|
||||
#. module: client_contracts
|
||||
#: model:ir.model.fields,help:client_contracts.field_res_partner_contract_annex_number
|
||||
#: model:ir.model.fields,help:client_contracts.field_res_partner_contract_annex_counter
|
||||
msgid "Counter of Contract Annexes"
|
||||
msgstr "Счётчик приложений к договору"
|
||||
|
||||
@ -303,6 +305,11 @@ msgstr "Создано"
|
||||
msgid "Created on"
|
||||
msgstr "Создан"
|
||||
|
||||
#. module: client_contracts
|
||||
#: model:ir.model.fields,field_description:client_contracts.field_res_partner_contract_annex_currency_id
|
||||
msgid "Currency"
|
||||
msgstr "Валюта"
|
||||
|
||||
#. module: client_contracts
|
||||
#: model:ir.model.fields,field_description:client_contracts.field_res_partner_contract_date_conclusion_fix
|
||||
msgid "Date of manual conclusion"
|
||||
@ -391,6 +398,11 @@ msgstr "Имя документа"
|
||||
msgid "Document Template"
|
||||
msgstr "Шаблон документа"
|
||||
|
||||
#. module: client_contracts
|
||||
#: model:ir.actions.act_window,name:client_contracts.res_partner_document_template_action
|
||||
msgid "Document Templates"
|
||||
msgstr "Шаблоны документов"
|
||||
|
||||
#. module: client_contracts
|
||||
#: model:ir.model.fields,field_description:client_contracts.field_res_partner_contract_annex_design_doc_cost
|
||||
msgid "Documentation Design Cost"
|
||||
@ -828,7 +840,7 @@ msgid "Print Form of Contract"
|
||||
msgstr "Форма печати договора"
|
||||
|
||||
#. module: client_contracts
|
||||
#: code:addons/client_contracts/models/res_partner_contract_annex.py:104
|
||||
#: code:addons/client_contracts/models/res_partner_contract_annex.py:111
|
||||
#, python-format
|
||||
msgid "Print Form of Contract Annex"
|
||||
msgstr "Форма печати приложения к договору"
|
||||
@ -952,7 +964,7 @@ msgid "Sole Proprietor"
|
||||
msgstr "Индивидуальный предприниматель"
|
||||
|
||||
#. module: client_contracts
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:25
|
||||
#: code:addons/client_contracts/models/res_partner_document_template.py:28
|
||||
#: selection:res.partner.document.template,document_type_name:0
|
||||
#, python-format
|
||||
msgid "Specification"
|
||||
@ -1003,7 +1015,7 @@ msgid "Template Type"
|
||||
msgstr "Тип шаблона"
|
||||
|
||||
#. module: client_contracts
|
||||
#: model:ir.ui.menu,name:client_contracts.res_partner_menu_contracts_templates_
|
||||
#: model:ir.ui.menu,name:client_contracts.res_partner_menu_contracts_templates
|
||||
msgid "Templates"
|
||||
msgstr "Шаблоны"
|
||||
|
||||
@ -1028,6 +1040,11 @@ msgstr "Transient Field Ids Hidden"
|
||||
msgid "Type of document"
|
||||
msgstr "Вид документа"
|
||||
|
||||
#. module: client_contracts
|
||||
#: model:ir.model.fields,help:client_contracts.field_res_partner_contract_annex_currency_id
|
||||
msgid "Utility field to express amount currency"
|
||||
msgstr "Служебное поле, чтобы выразить суммы в валюте"
|
||||
|
||||
#. module: client_contracts
|
||||
#: model:ir.model.fields,field_description:client_contracts.field_res_partner_contract_field_transient_value
|
||||
msgid "Value"
|
||||
@ -1068,23 +1085,13 @@ msgstr "Год"
|
||||
msgid "i.e. Ural Bank for Reconstruction and Development"
|
||||
msgstr "напр. «Уральский банк реконструкции и развития»"
|
||||
|
||||
#. module: client_contracts
|
||||
#: model:ir.actions.act_window,name:client_contracts.res_partner_contract_field_action
|
||||
msgid "res.partner.contract.field.action"
|
||||
msgstr "res.partner.contract.field.action"
|
||||
|
||||
#. module: client_contracts
|
||||
#: model:ir.model,name:client_contracts.model_res_partner_contract_wizard
|
||||
msgid "res.partner.contract.wizard"
|
||||
msgstr "res.partner.contract.wizard"
|
||||
|
||||
#. module: client_contracts
|
||||
#: model:ir.actions.act_window,name:client_contracts.res_partner_document_template_action
|
||||
msgid "res.partner.document.template.action"
|
||||
msgstr "res.partner.document.template.action"
|
||||
|
||||
#. module: client_contracts
|
||||
#: code:addons/client_contracts/models/res_partner_contract_annex.py:80
|
||||
#: code:addons/client_contracts/models/res_partner_contract_annex.py:64
|
||||
#, python-format
|
||||
msgid "{name} from {date}"
|
||||
msgstr "{name} от {date}"
|
||||
|
@ -1,7 +1,6 @@
|
||||
import datetime
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.tools.misc import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
|
||||
|
||||
from ..utils import MODULE_NAME
|
||||
from ..utils.misc import Extension, IDocument
|
||||
@ -110,7 +109,11 @@ class PartnerContract(models.Model, IDocument, Extension):
|
||||
|
||||
def get_filename_by_document_template(self, document_template_id):
|
||||
return _("{type} {number} from {date}").format(
|
||||
type=_(dict(document_template_id._fields['document_type'].selection).get(document_template_id.document_type)),
|
||||
type=_(
|
||||
dict(document_template_id._fields["document_type"].selection).get(
|
||||
document_template_id.document_type
|
||||
)
|
||||
),
|
||||
number=self.name,
|
||||
date=self.get_date().strftime("%d.%m.%Y"),
|
||||
)
|
||||
@ -123,10 +126,9 @@ class PartnerContract(models.Model, IDocument, Extension):
|
||||
"""
|
||||
date = self.date_conclusion_fix or self.date_conclusion
|
||||
if date:
|
||||
date = datetime.datetime.strptime(date, DEFAULT_SERVER_DATE_FORMAT)
|
||||
date = self.parse_odoo_date(date)
|
||||
else:
|
||||
date = self.create_date
|
||||
date = datetime.datetime.strptime(date, DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
date = self.parse_odoo_datetime(self.create_date)
|
||||
return date
|
||||
|
||||
def _(self, arg):
|
||||
|
@ -17,24 +17,26 @@ class ContractOrderAnnex(models.Model, IDocument, Extension):
|
||||
contract_id = fields.Many2one(
|
||||
"res.partner.contract", string="Contract", readonly=True,
|
||||
)
|
||||
partner_id = fields.Many2one(related="contract_id.partner_id")
|
||||
company_id = fields.Many2one("res.partner", related="contract_id.company_id",)
|
||||
partner_id = fields.Many2one("res.partner", related="contract_id.partner_id",)
|
||||
order_id = fields.Many2one(
|
||||
"sale.order",
|
||||
string="Order",
|
||||
required=True,
|
||||
help="Orders with this partner which are not uses in annexes yet",
|
||||
required=True,
|
||||
)
|
||||
date_conclusion = fields.Date(
|
||||
string="Conclusion Date", default=fields.Date.today(),
|
||||
)
|
||||
number = fields.Integer(string="№",help="Counter of Contract Annexes")
|
||||
counter = fields.Integer(string="№", help="Counter of Contract Annexes",)
|
||||
currency_id = fields.Many2one(related="company_id.currency_id", readonly=True,)
|
||||
|
||||
development_period = fields.Integer("Product Development Period (days)",)
|
||||
|
||||
design_cost = fields.Float(string="Design Cost",)
|
||||
design_cost = fields.Monetary(string="Design Cost",)
|
||||
|
||||
design_doc_period = fields.Integer(string="Documentation Design Period (days)",)
|
||||
design_doc_cost = fields.Float(string="Documentation Design Cost",)
|
||||
design_doc_cost = fields.Monetary(string="Documentation Design Cost",)
|
||||
|
||||
delivery_address = fields.Char(string="Delivery Address",)
|
||||
delivery_period = fields.Integer(string="Delivery Period (days)")
|
||||
@ -43,12 +45,41 @@ class ContractOrderAnnex(models.Model, IDocument, Extension):
|
||||
installation_period = fields.Integer(string="Installation Period (days)",)
|
||||
installation_cost = fields.Integer(string="Installation Cost",)
|
||||
|
||||
total_cost = fields.Float(string="Total Cost",)
|
||||
total_cost = fields.Monetary(string="Total Cost",)
|
||||
|
||||
payment_part_one = fields.Float(string="Payment 1 Part (%)", default=100)
|
||||
payment_part_two = fields.Float(string="Payment 2 Part (%)",)
|
||||
payment_part_three = fields.Float(string="Payment 3 Part (%)",)
|
||||
|
||||
@api.multi
|
||||
@api.depends("name")
|
||||
def _compute_display_name(self):
|
||||
for record in self:
|
||||
record.display_name = "№{} {}".format(
|
||||
record.counter or record.contract_id.contract_annex_number, record.name
|
||||
)
|
||||
|
||||
@api.depends("specification_name", "contract_id", "order_id")
|
||||
def _compute_specification_name(self):
|
||||
self.specification_name = _("{name} from {date}").format(
|
||||
name="{}-{}".format(self.contract_id.name, self.order_id.name),
|
||||
date=self.contract_id.get_date().strftime("%d.%m.%Y"),
|
||||
)
|
||||
|
||||
@api.onchange("order_id")
|
||||
def _domain_order_id(self):
|
||||
"""Using domain function because of
|
||||
simple domain does not working properly because of
|
||||
contract_id is still False"""
|
||||
return {
|
||||
"domain": {
|
||||
"order_id": [
|
||||
("partner_id", "=", self.contract_id.partner_id.id),
|
||||
("contract_annex_id", "=", False),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@api.onchange("order_id")
|
||||
def _onchange_order_id(self):
|
||||
contract_number = self.contract_id.name
|
||||
@ -58,30 +89,6 @@ class ContractOrderAnnex(models.Model, IDocument, Extension):
|
||||
contract=contract_number, order=order_number,
|
||||
)
|
||||
|
||||
# Compute domain for order_id because of bug with
|
||||
# not working correctly domain in model
|
||||
return {
|
||||
"domain": {
|
||||
"order_id": [
|
||||
("partner_id", "=", self.contract_id.partner_id.id),
|
||||
("contract_annex_id", "=", False),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@api.multi
|
||||
@api.depends('name')
|
||||
def _compute_display_name(self):
|
||||
for record in self:
|
||||
record.display_name = "№{} {}".format(record.number or record.contract_id.contract_annex_number, record.name)
|
||||
|
||||
@api.depends('specification_name', 'contract_id', 'order_id')
|
||||
def _compute_specification_name(self):
|
||||
self.specification_name = _("{name} from {date}").format(
|
||||
name="{}-{}".format(self.contract_id.name, self.order_id.name),
|
||||
date=self.contract_id.get_date().strftime("%d.%m.%Y"),
|
||||
)
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
record = super().create(values)
|
||||
@ -90,8 +97,8 @@ class ContractOrderAnnex(models.Model, IDocument, Extension):
|
||||
record.order_id.contract_annex_id = record.id
|
||||
|
||||
# Counter
|
||||
record.number = record.contract_id.contract_annex_number
|
||||
record.contract_id.contract_annex_number += 1
|
||||
record.counter = record.contract_id.contract_annex_number
|
||||
record.contract_id.contract_annex_number += 1 # TODO: should I use a sequence?
|
||||
|
||||
return record
|
||||
|
||||
@ -111,30 +118,41 @@ class ContractOrderAnnex(models.Model, IDocument, Extension):
|
||||
}
|
||||
|
||||
def get_name_by_document_template(self, document_template_id):
|
||||
return {
|
||||
"specification": "{number} {name}",
|
||||
"approval_list": "{number}.1 {name}-1",
|
||||
"act_at": "{number}.2 {name}-2",
|
||||
"act_ad": "{number}.3 {name}-3",
|
||||
}.get(document_template_id.document_type_name, "Unknown").format(
|
||||
number=self.number,
|
||||
name=self.name,
|
||||
return (
|
||||
{
|
||||
"specification": "{counter} {name}",
|
||||
"approval_list": "{counter}.1 {name}-1",
|
||||
"act_at": "{counter}.2 {name}-2",
|
||||
"act_ad": "{counter}.3 {name}-3",
|
||||
}
|
||||
.get(document_template_id.document_type_name, "Unknown")
|
||||
.format(counter=self.counter, name=self.name,)
|
||||
)
|
||||
|
||||
def get_filename_by_document_template(self, document_template_id):
|
||||
return "{type} №{name}".format(
|
||||
type=_(dict(document_template_id._fields['document_type'].selection).get(document_template_id.document_type)),
|
||||
name={
|
||||
"bill": "{number} {type} {name}",
|
||||
"specification": "{number} {type} {name}",
|
||||
"approval_list": "{number}.1 {type} {name}-1",
|
||||
"act_at": "{number}.2 {type} {name}-2",
|
||||
"act_ad": "{number}.3 {type} {name}-3",
|
||||
}.get(document_template_id.document_type_name).format(
|
||||
number=self.number,
|
||||
type=_(dict(document_template_id._fields['document_type_name'].selection).get(document_template_id.document_type_name)),
|
||||
name=self.name,
|
||||
type=_(
|
||||
dict(document_template_id._fields["document_type"].selection).get(
|
||||
document_template_id.document_type
|
||||
)
|
||||
),
|
||||
name={
|
||||
"bill": "{counter} {type} {name}",
|
||||
"specification": "{counter} {type} {name}",
|
||||
"approval_list": "{counter}.1 {type} {name}-1",
|
||||
"act_at": "{counter}.2 {type} {name}-2",
|
||||
"act_ad": "{counter}.3 {type} {name}-3",
|
||||
}
|
||||
.get(document_template_id.document_type_name)
|
||||
.format(
|
||||
counter=self.counter,
|
||||
type=_(
|
||||
dict(
|
||||
document_template_id._fields["document_type_name"].selection
|
||||
).get(document_template_id.document_type_name)
|
||||
),
|
||||
name=self.name,
|
||||
),
|
||||
)
|
||||
|
||||
def modf(self, arg):
|
||||
|
@ -4,11 +4,14 @@ from odoo import _, fields, models
|
||||
class DocumentTemplate(models.Model):
|
||||
_name = "res.partner.document.template"
|
||||
_description = "Document Template"
|
||||
_order = "template_type desc,company_type,sequence"
|
||||
_order = "company_type,document_type,sequence"
|
||||
|
||||
name = fields.Char()
|
||||
attachment_id = fields.Many2one(
|
||||
"ir.attachment", string="Template Attachment", ondelete="cascade", required=True,
|
||||
"ir.attachment",
|
||||
string="Template Attachment",
|
||||
ondelete="cascade",
|
||||
required=True,
|
||||
)
|
||||
document_type = fields.Selection(
|
||||
string="Type of document",
|
||||
@ -16,7 +19,7 @@ class DocumentTemplate(models.Model):
|
||||
("contract", _("Contract")),
|
||||
("annex", _("Annex")),
|
||||
("addition", _("Addition")),
|
||||
]
|
||||
],
|
||||
)
|
||||
document_type_name = fields.Selection(
|
||||
string="Document",
|
||||
@ -26,7 +29,7 @@ class DocumentTemplate(models.Model):
|
||||
("approval_list", _("Approval List")),
|
||||
("act_at", _("Act of Acceptance and Transfer")),
|
||||
("act_ad", _("Act of Acceptance and Delivery")),
|
||||
]
|
||||
],
|
||||
)
|
||||
company_type = fields.Selection(
|
||||
selection=[
|
||||
|
@ -1,22 +1,26 @@
|
||||
import inspect
|
||||
import datetime as dt
|
||||
import inspect
|
||||
|
||||
from odoo import fields
|
||||
from odoo.tools.misc import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from odoo.tools.misc import (DEFAULT_SERVER_DATE_FORMAT,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
|
||||
|
||||
class IDocument(object):
|
||||
"""Class must be used as an interface for create new document based model"""
|
||||
|
||||
def get_name_by_document_template(self, document_template_id: fields.Many2one):
|
||||
raise NotImplementedError('Method {} is not implemented'.format(inspect.currentframe().f_code.co_name))
|
||||
raise NotImplementedError(
|
||||
"Method {} is not implemented".format(inspect.currentframe().f_code.co_name)
|
||||
)
|
||||
|
||||
def get_filename_by_document_template(self, document_template_id: fields.Many2one):
|
||||
raise NotImplementedError('Method {} is not implemented'.format(inspect.currentframe().f_code.co_name))
|
||||
raise NotImplementedError(
|
||||
"Method {} is not implemented".format(inspect.currentframe().f_code.co_name)
|
||||
)
|
||||
|
||||
|
||||
class Extension(object):
|
||||
|
||||
def parse_odoo_date(self, date: str):
|
||||
return dt.datetime.strptime(date, DEFAULT_SERVER_DATE_FORMAT)
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
<!-- res.partner.contract.field action window -->
|
||||
<record id="res_partner_contract_field_action" model="ir.actions.act_window">
|
||||
<field name="name">res.partner.contract.field.action</field>
|
||||
<field name="name">Contract Fields</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">res.partner.contract.field</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
<!-- res.partner.document.template action window -->
|
||||
<record id="res_partner_document_template_action" model="ir.actions.act_window">
|
||||
<field name="name">res.partner.document.template.action</field>
|
||||
<field name="name">Document Templates</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">res.partner.document.template</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
@ -87,7 +87,7 @@
|
||||
parent="res_partner_menu_contracts"
|
||||
sequence="1"/>
|
||||
|
||||
<menuitem id="res_partner_menu_contracts_templates_"
|
||||
<menuitem id="res_partner_menu_contracts_templates"
|
||||
name="Templates"
|
||||
parent="res_partner_menu_contracts"
|
||||
action="res_partner_document_template_action"
|
||||
|
@ -12,6 +12,7 @@
|
||||
<sheet>
|
||||
<group name="options" invisible="1">
|
||||
<field name="display_name" invisible="1"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
</group>
|
||||
<group name="info" string="Info">
|
||||
<field name="name" placeholder="Leave empty for compute"/>
|
||||
|
20
views/res_partner_contract_field.xml
Normal file
20
views/res_partner_contract_field.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<!-- res.partner.contract.field tree view -->
|
||||
<record id="res_partner_contract_field_view_tree" model="ir.ui.view">
|
||||
<field name="name">res.partner.contract.field.view.tree</field>
|
||||
<field name="model">res.partner.contract.field</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="name"/>
|
||||
<field name="description"/>
|
||||
<field name="technical_name"/>
|
||||
<field name="visible"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
@ -1,5 +1,4 @@
|
||||
import base64
|
||||
import logging
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
@ -7,35 +6,32 @@ from odoo.exceptions import ValidationError
|
||||
from ..utils import MODULE_NAME
|
||||
from ..utils.docxtpl import get_document_from_values_stream
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ContractWizard(models.TransientModel):
|
||||
_name = "res.partner.contract.wizard"
|
||||
|
||||
def _get_default_partner(self):
|
||||
current_id = self.env.context.get("active_id")
|
||||
partner_id = self.env[self.active_model].browse(current_id).partner_id
|
||||
return partner_id
|
||||
def _default_target(self):
|
||||
return "{model},{target_id}".format(
|
||||
model=self.active_model, target_id=int(self.env.context.get("self_id"))
|
||||
)
|
||||
|
||||
def _get_default_template(self):
|
||||
partner_id = self._get_default_partner()
|
||||
def _default_document_template(self):
|
||||
return self.env["res.partner.document.template"].search(self._get_template_domain(), limit=1)
|
||||
|
||||
def _get_template_domain(self):
|
||||
template_type = {
|
||||
"res.partner.contract": "contract",
|
||||
"res.partner.contract.annex": "annex",
|
||||
}.get(self.active_model, False)
|
||||
company_type = (
|
||||
partner_id.company_form if partner_id.is_company else "person"
|
||||
self.partner_id.company_form if self.partner_id.is_company else "person"
|
||||
)
|
||||
|
||||
document_template_domain = [
|
||||
("template_type", "=", template_type),
|
||||
("company_type", "=", company_type),
|
||||
]
|
||||
|
||||
return self.env["res.partner.document.template"].search(
|
||||
document_template_domain, limit=1
|
||||
)
|
||||
return document_template_domain
|
||||
|
||||
target = fields.Reference(
|
||||
selection=[
|
||||
@ -43,13 +39,23 @@ class ContractWizard(models.TransientModel):
|
||||
("res.partner.contract.annex", "Contract Annex"),
|
||||
],
|
||||
string="Target",
|
||||
default=_default_target,
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
"res.partner", string="Company", compute="_compute_company_id",
|
||||
)
|
||||
partner_id = fields.Many2one(
|
||||
"res.partner", string="Partner", compute="_compute_partner_id",
|
||||
)
|
||||
document_name = fields.Char(
|
||||
string="Document Name", compute="_compute_document_name"
|
||||
)
|
||||
company_id = fields.Many2one("res.partner", string="Company")
|
||||
partner_id = fields.Many2one("res.partner", string="Partner", default=_get_default_partner)
|
||||
document_template = fields.Many2one(
|
||||
"res.partner.document.template", string="Document Template", default=_get_default_template,
|
||||
"res.partner.document.template",
|
||||
string="Document Template",
|
||||
default=_default_document_template,
|
||||
readonly=False,
|
||||
)
|
||||
document_name = fields.Char(string="Document Name", compute='_compute_document_name')
|
||||
transient_field_ids = fields.One2many(
|
||||
"res.partner.contract.field.transient",
|
||||
"_contract_wizard_id",
|
||||
@ -59,14 +65,34 @@ class ContractWizard(models.TransientModel):
|
||||
"res.partner.contract.field.transient", "_contract_wizard_id",
|
||||
)
|
||||
|
||||
@api.depends("company_id", "target")
|
||||
def _compute_company_id(self):
|
||||
if self.target:
|
||||
self.company_id = self.target.company_id
|
||||
|
||||
@api.depends("partner_id", "target")
|
||||
def _compute_partner_id(self):
|
||||
if self.target:
|
||||
self.partner_id = self.target.partner_id
|
||||
|
||||
@api.depends("document_name", "document_template", "target")
|
||||
def _compute_document_name(self):
|
||||
self.document_name = self.target.get_name_by_document_template(
|
||||
self.document_template
|
||||
)
|
||||
|
||||
@api.constrains("document_template")
|
||||
def _check_document_template(self):
|
||||
if not self.document_template:
|
||||
raise ValidationError("You did not set up the template...")
|
||||
|
||||
@api.depends('document_name', 'document_template', 'target')
|
||||
def _compute_document_name(self):
|
||||
self.document_name = self.target.get_name_by_document_template(self.document_template)
|
||||
@api.onchange('document_template')
|
||||
def _domain_document_template(self):
|
||||
return {
|
||||
"domain": {
|
||||
"document_template": self._get_template_domain(),
|
||||
}
|
||||
}
|
||||
|
||||
@api.onchange("document_template")
|
||||
def _onchange_document_template(self):
|
||||
@ -79,25 +105,6 @@ class ContractWizard(models.TransientModel):
|
||||
[("technical_name", "=", technical_name),]
|
||||
)
|
||||
|
||||
# A record is the model called from (manually set with context)
|
||||
self.target = "{model},{target_id}".format(
|
||||
model=self.active_model, target_id=int(self.env.context.get("self_id"))
|
||||
)
|
||||
|
||||
# Check for model and get this meta fields
|
||||
company_id = (
|
||||
self.target.company_id
|
||||
if hasattr(self.target, "company_id")
|
||||
else self.target.contract_id.company_id
|
||||
)
|
||||
partner_id = (
|
||||
self.target.partner_id
|
||||
if hasattr(self.target, "partner_id")
|
||||
else self.target.contract_id.partner_id
|
||||
)
|
||||
self.company_id = company_id
|
||||
self.partner_id = partner_id
|
||||
|
||||
model_to_action = {
|
||||
"res.partner.contract": "action_get_contract_context",
|
||||
"res.partner.contract.annex": "action_get_annex_context",
|
||||
@ -134,41 +141,19 @@ class ContractWizard(models.TransientModel):
|
||||
self.transient_field_ids - self.transient_field_ids_hidden
|
||||
)
|
||||
|
||||
# TODO: remove replicate of code
|
||||
template_type = {
|
||||
"res.partner.contract": "contract",
|
||||
"res.partner.contract.annex": "annex",
|
||||
}.get(self.active_model, False)
|
||||
company_type = (
|
||||
self.partner_id.company_form if self.partner_id.is_company else "person"
|
||||
)
|
||||
|
||||
return {"domain": {"document_template": [("template_type", "=", template_type),("company_type", "=", company_type),],}}
|
||||
# Other
|
||||
|
||||
@api.multi
|
||||
def get_docx_contract(self):
|
||||
template = self.document_template.attachment_id
|
||||
template_path = template._full_path(template.store_fname)
|
||||
|
||||
path_to_template = template._full_path(template.store_fname)
|
||||
|
||||
fields = {
|
||||
transient_field.technical_name: transient_field.value
|
||||
for transient_field in (
|
||||
self.transient_field_ids + self.transient_field_ids_hidden
|
||||
)
|
||||
if transient_field.technical_name and transient_field.value
|
||||
}
|
||||
if self.target._name == "res.partner.contract.annex":
|
||||
fields.update({
|
||||
"annex_name": self.document_name,
|
||||
"specification_name": self.target.specification_name,
|
||||
})
|
||||
|
||||
binary_data = get_document_from_values_stream(path_to_template, fields).read()
|
||||
payload = self.payload()
|
||||
binary_data = get_document_from_values_stream(template_path, payload).read()
|
||||
encoded_data = base64.b64encode(binary_data)
|
||||
|
||||
attachment_name = self.target.get_filename_by_document_template(self.document_template) or "Unknown"
|
||||
attachment_name = "{}.docx".format(attachment_name)
|
||||
get_fn = self.target.get_filename_by_document_template
|
||||
attachment_name = "{}.docx".format(get_fn(self.document_template or "Unknown"))
|
||||
|
||||
document_as_attachment = self.env["ir.attachment"].create(
|
||||
{
|
||||
@ -179,7 +164,51 @@ class ContractWizard(models.TransientModel):
|
||||
}
|
||||
)
|
||||
|
||||
# Send message with attachment to a mail.thread of the company
|
||||
return self.afterload(document_as_attachment)
|
||||
|
||||
def payload(self):
|
||||
# Collect fields into a key-value structure
|
||||
fields = {
|
||||
transient_field.technical_name: transient_field.value
|
||||
for transient_field in (
|
||||
self.transient_field_ids + self.transient_field_ids_hidden
|
||||
)
|
||||
if transient_field.technical_name and transient_field.value
|
||||
}
|
||||
# Extend with special case
|
||||
if self.target._name == "res.partner.contract.annex":
|
||||
fields.update(
|
||||
{
|
||||
"annex_name": self.document_name,
|
||||
"specification_name": self.target.specification_name,
|
||||
}
|
||||
)
|
||||
# Extend with order product lines
|
||||
if hasattr(self.target, "order_id") and self.target.order_id.order_line:
|
||||
def number_generator(n=1):
|
||||
while (True):
|
||||
yield n
|
||||
n += 1
|
||||
|
||||
counter = number_generator()
|
||||
|
||||
fields.update(
|
||||
{
|
||||
"order_products": [
|
||||
{
|
||||
"number": next(counter),
|
||||
"label": item.product_id.name,
|
||||
"count": item.product_uom_qty,
|
||||
"unit": item.product_uom.name,
|
||||
"cost": item.price_unit,
|
||||
"amount": item.price_subtotal,
|
||||
} for item in self.target.order_id.order_line or []
|
||||
]
|
||||
}
|
||||
)
|
||||
return fields
|
||||
|
||||
def afterload(self, result):
|
||||
res_id = self.target.id
|
||||
if hasattr(self.target, "contract_id"):
|
||||
res_id = self.target.contract_id.id
|
||||
@ -189,11 +218,11 @@ class ContractWizard(models.TransientModel):
|
||||
"model": "res.partner.contract",
|
||||
"res_id": res_id,
|
||||
"message_type": "comment",
|
||||
"attachment_ids": [(4, document_as_attachment.id, False)],
|
||||
"attachment_ids": [(4, result.id, False)],
|
||||
}
|
||||
)
|
||||
|
||||
return document_as_attachment
|
||||
return result
|
||||
|
||||
@property
|
||||
def active_model(self):
|
||||
|
Loading…
x
Reference in New Issue
Block a user