104 lines
5.8 KiB
Python
104 lines
5.8 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
from odoo import fields, models, api, _
|
|
from odoo.exceptions import ValidationError
|
|
|
|
USE_TYPE_SELECTION = [
|
|
('use or consumption', 'Use or consumption'),
|
|
('resale', 'Resale'),
|
|
('agricultural production', 'Agricultural production'),
|
|
('production', 'Production'),
|
|
('fixed assets', 'Fixed assets'),
|
|
('notApplicable', 'Not applicable'),
|
|
]
|
|
|
|
|
|
class ProductTemplate(models.Model):
|
|
_inherit = 'product.template'
|
|
|
|
def _l10n_br_property_service_code_origin_id_domain(self):
|
|
return [("city_id", "=", self.env.company.partner_id.sudo().city_id.id)]
|
|
|
|
l10n_br_cest_code = fields.Char(
|
|
string='CEST Code',
|
|
help='A tax classification code used to identify goods and products subject to tax substitution under ICMS regulations.'
|
|
'It helps determine the applicable tax treatment and procedures for specific items.'
|
|
'Check if your product is subject or not to this in https://www.codigocest.com.br/.'
|
|
)
|
|
l10n_br_ncm_code_id = fields.Many2one('l10n_br.ncm.code', string="Mercosul NCM Code", help="Brazil: Use this field to specify the classification code of the item, either the NCM (Nomenclatura Comum do Mercosul) for goods or the LC116 for services.")
|
|
l10n_br_property_service_code_origin_id = fields.Many2one(
|
|
"l10n_br.service.code",
|
|
domain=_l10n_br_property_service_code_origin_id_domain,
|
|
string="Service Code Origin",
|
|
company_dependent=True,
|
|
help="Brazil: City service code where the provider is registered.",
|
|
)
|
|
l10n_br_labor = fields.Boolean(
|
|
"Labor Assignment", help="Brazil: If your service involves labor, select this checkbox."
|
|
)
|
|
l10n_br_service_code_ids = fields.Many2many(
|
|
"l10n_br.service.code",
|
|
string="Service Codes",
|
|
help="Brazil: The service codes for this product, as defined by the cities in which you wish to sell it. If no city-specific code is provided, the Service Code Origin will be used instead.",
|
|
)
|
|
l10n_br_company_city_id = fields.Many2one(
|
|
"res.city",
|
|
compute="_compute_l10n_br_company_city_id",
|
|
help="Technical field used to determined the default of a service code when configured as a service code origin.",
|
|
)
|
|
|
|
# technical names of these selections fields are directly passed to the API
|
|
l10n_br_source_origin = fields.Selection([
|
|
('0', 'National goods - except those treated in codes 3,4, 5 and 8'),
|
|
('1', 'Foreign goods - Imported directly by seller, except those in code 6'),
|
|
('2', 'Foreign goods - Acquired in the internal market (inside Brazil), except those in code 7'),
|
|
('3', 'National goods - Merchandise or goods with imported content above 40% and with less than or equal to 70%'),
|
|
('4',
|
|
'National goods from production following \'standard basic processes\' as stablished by legislation (standard basic processes are devised to separate simple assembly from manufaturing processes)'),
|
|
('5', 'National goods - Merchandise or goods with imported content equal or below 40%'),
|
|
('6',
|
|
'Foreign goods - Directly imported by Seller, without a National Equivalent as listed by Comex and natural gas'),
|
|
('7', 'Foreign goods - Acquired inside Brazil, without a National Equivalent as listed by Comex and natural gas'),
|
|
('8', 'National goods - Merchandise or goods with imported content above 70% (pt)'),
|
|
],
|
|
string='Source of Origin',
|
|
help='Brazil: Product Source of Origin indicates if the product has a foreing or national origin with different variations and characteristics dependin on the product use case'
|
|
)
|
|
l10n_br_sped_type = fields.Selection([
|
|
('FOR PRODUCT', 'For product'),
|
|
('FOR MERCHANDISE', 'For merchandise'),
|
|
('NO RESTRICTION', 'No restriction'),
|
|
('SERVICE', 'Service'),
|
|
('FEEDSTOCK', 'Feedstock'),
|
|
('FIXED ASSETS', 'Fixed assets'),
|
|
('PACKAGING', 'Packaging'),
|
|
('PRODUCT IN PROCESS', 'Product in process'),
|
|
('SUBPRODUCT', 'Subproduct'),
|
|
('INTERMEDIATE PRODUCT', 'Intermediate product'),
|
|
('MATERIAL FOR USAGE AND CONSUMPTION', 'Material for usage and consumption'),
|
|
('OTHER INPUTS', 'Other inputs'),
|
|
], string='SPED Fiscal Product Type', help='Brazil: Fiscal product type according to SPED list table')
|
|
l10n_br_use_type = fields.Selection(USE_TYPE_SELECTION, string='Purpose of Use', help='Brazil: indicate what is the usage purpose for this product')
|
|
l10n_br_transport_cost_type = fields.Selection([
|
|
('freight', 'Freight'),
|
|
('insurance', 'Insurance'),
|
|
('other', 'Other costs')
|
|
], string='Transport Cost Type', help='Brazil: select whether this product will be use to register Freight, Insurance or Other Costs amounts related to the transaction.')
|
|
|
|
@api.constrains("l10n_br_service_code_ids")
|
|
def _check_l10n_br_service_code_ids(self):
|
|
for product in self:
|
|
for (_company, city), codes in product.l10n_br_service_code_ids.grouped(lambda code: (code.company_id, code.city_id)).items():
|
|
if len(codes) > 1:
|
|
raise ValidationError(_("Can't have more than one service code for %s.", city.display_name))
|
|
|
|
@api.depends("company_id")
|
|
@api.depends_context("company")
|
|
def _compute_l10n_br_company_city_id(self):
|
|
for product in self:
|
|
company = product.company_id or self.env.company
|
|
product.l10n_br_company_city_id = company.partner_id.city_id
|
|
|
|
def _l10n_br_is_only_allowed_on_service_invoice(self):
|
|
"""Service products are only allowed on a goods invoice if it's a transportation service."""
|
|
return not self.l10n_br_transport_cost_type and self.type == "service"
|