odoo/ext/custom-addons/dp_custom/models/product.py

292 lines
12 KiB
Python

# -*- coding: utf-8 -*-
##############################################################################
#
# datenpol gmbh
# Copyright (C) 2013-TODAY datenpol gmbh (<http://www.datenpol.at/>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import json
import requests
from odoo.addons.component.core import Component
from odoo import tools, fields, models, api, _
from odoo.exceptions import ValidationError
from odoo.addons.queue_job.job import job
import ssl
try:
_create_unverified_https_context = ssl._create_unverified_context
except AttributeError:
# Legacy Python that doesn't verify HTTPS certificates by default
pass
else:
# Handle target environment that doesn't support HTTPS verification
ssl._create_default_https_context = _create_unverified_https_context
class ReportIntrastatCode(models.Model):
_inherit = "report.intrastat.code"
active = fields.Boolean(string='Active', default=True, help="If unchecked, it will allow you to hide the code without removing it.")
class ProductTemplate(models.Model):
_inherit = "product.template"
intrastat_id = fields.Many2one('report.intrastat.code', string='Intrastat Code')
class ProductXCategory(models.Model):
_name = 'product.xcategory'
_description = 'X-Kategorie'
_order = 'name'
name = fields.Char(string='Bezeichnung', required=True)
_sql_constraints = [
('name_uniq', 'unique(name)', 'Die Bezeichnung muss eindeutig sein')
]
class ProductTemplate(models.Model):
_name = 'product.template'
_inherit = ['product.template', 'dp_custom.helper']
SURFACE_OPTIONS = [
('m', 'Maserrichtung'),
('u', 'Einfärbig')
]
length = fields.Float(string='Länge in mm')
width = fields.Float(string='Breite in mm')
thickness = fields.Float(string='Dicke in mm', help='Echte Dicke in mm')
height = fields.Float(string='Höhe in mm')
surface = fields.Selection(SURFACE_OPTIONS, string='Oberfläche')
is_internal = fields.Boolean()
xcat_id = fields.Many2one(comodel_name='product.xcategory', string='X-Kategorie')
material_type_id = fields.Many2one(comodel_name='material.type', string='Materialtyp')
assembly_line_ids = fields.Many2many(comodel_name='res.line', string='Produktionslinien')
notes = fields.Text(string='Notizen')
can_be_sold_unconfigured = fields.Boolean(string='Darf unkonfiguriert verkauft werden')
manufacturing_number = fields.Char(string='Herstellnummer')
product_color = fields.Char(string='Farbe')
suppl_ids = fields.One2many('product.supplierinfo', 'product_tmpl_id')
@api.onchange('length', 'width', 'thickness', 'height')
def _onchange_measures(self):
if self.length>0 and self.width>0 and self.thickness>0:
self.volume = self.length*self.width*self.thickness / (1000*1000*1000)
elif self.length>0 and self.width>0 and self.height>0:
self.volume = self.length*self.width*self.height / (1000*1000*1000)
@api.model
def create_product(self, vals):
"""
SST-10
:param vals:
:return:
"""
self.check_not_specified_fields(vals)
vals = self.correct_values(vals)
product_template = self.with_context(active_test=False).search([('default_code', '=', vals['default_code'])])
pid = 0
if product_template:
# default_code may not be changed if there is already an inventory_line (in other company), so we remove it from the dict
vals.pop('default_code',None)
if product_template['manufacturing_number']:
vals.pop('manufacturing_number',None)
product_template.write(vals)
pid = product_template.id
else:
if vals['active']:
res = self.create(vals)
pid = res.id
return True, pid
@api.model
def correct_values(self, vals):
if vals.get('xcat_id', False):
xcat = self.env['product.xcategory'].search([('name', '=', vals['xcat_id'])])
if xcat:
vals['xcat_id'] = xcat.id
else:
raise ValidationError(
_("X-Kategorie \'%s\' kann nicht zugeordnet werden") % vals['xcat_id'])
if vals.get('categ_id', False):
categ_id = self.env['product.category'].search([('code', '=', vals['categ_id'])])
if categ_id:
vals['categ_id'] = categ_id.id
else:
raise ValidationError(
_("Kategorie \'%s\' kann nicht zugeordnet werden") % vals['categ_id'])
if vals.get('material_type_id', False):
material_type = self.env['material.type'].search([('name', '=', vals['material_type_id'])])
if material_type:
vals['material_type_id'] = material_type.id
else:
raise ValidationError(
_("Materialtyp \'%s\' kann nicht zugeordnet werden") % vals['material_type_id'])
if vals.get('intrastat_id', False):
intrastat = self.env['report.intrastat.code'].search([('name', '=', vals['intrastat_id'])])
if intrastat:
vals['intrastat_id'] = intrastat.id
else:
raise ValidationError(
_("Intrastat-Code \'%s\' kann nicht zugeordnet werden") % vals['intrastat_id'])
if vals.get('assembly_line_ids', False):
assembly_line_ids = []
for assembly_line_code in vals['assembly_line_ids']:
assembly_line = self.env['res.line'].search([('name', '=', assembly_line_code)])
if assembly_line:
assembly_line_ids.append(assembly_line.id)
else:
raise ValidationError(
_("Produktionslinie \'%s\' kann nicht zugeordnet werden") % assembly_line_code)
vals['assembly_line_ids'] = [(6, 0, assembly_line_ids)]
if vals.get('tax', False):
if vals['tax'] not in ["20% MwSt.", "10% MwSt.", "0% MwSt."]:
raise ValidationError(_("Die Steuer \'%s\' ist nicht gültig.") % vals['tax'])
tax = self.env['account.tax'].search([('name', '=', vals['tax'])])
if tax:
vals['taxes_id'] = [(6, 0, [tax.id])]
else:
raise ValidationError(_("Die Steuer \'%s\' kann nicht zugeordnet werden") % vals['tax'])
return vals
@api.model
def _get_specified_fields(self):
return ['default_code', 'name', 'length', 'width', 'thickness', 'surface', 'active', 'weight', 'is_internal',
'xcat_id', 'notes', 'material_type_id', 'intrastat_id', 'sale_ok', 'assembly_line_ids', 'list_price',
'height', 'categ_id', 'can_be_sold_unconfigured', 'image', 'tax', 'manufacturing_number']
class ProductCategory(models.Model):
_inherit = 'product.category'
code = fields.Char(string='Code')
class ProductPricelistItemEventListener(Component):
_name = 'product.pricelist.item.listener'
_inherit = 'base.event.listener'
_apply_on = ['product.pricelist.item']
# pricelist_mode = 'partner'
@api.model
def on_record_write(self, record, fields=None):
pricelist_mode = self.env['ir.config_parameter'].sudo().get_param('pricelist_mode')
if pricelist_mode == 'partner':
self.env['product.pricelist.item'].with_delay().job_mark_partner_for_export(record.pricelist_id.id)
else:
# self.env['product.pricelist.item'].with_delay().job_export_portal_pricelist(record.pricelist_id.id)
self.env['product.pricelist.item'].job_export_portal_pricelist(record.pricelist_id.id)
@api.model
def on_record_create(self, record, fields=None):
pricelist_mode = self.env['ir.config_parameter'].sudo().get_param('pricelist_mode')
if pricelist_mode == 'partner':
self.env['product.pricelist.item'].with_delay().job_mark_partner_for_export(record.pricelist_id.id)
else:
# self.env['product.pricelist.item'].with_delay().job_export_portal_pricelist(record.pricelist_id.id)
self.env['product.pricelist.item'].job_export_portal_pricelist(record.pricelist_id.id)
@api.model
def on_record_unlink(self, record):
pricelist_mode = self.env['ir.config_parameter'].sudo().get_param('pricelist_mode')
if pricelist_mode == 'partner':
self.env['product.pricelist.item'].with_delay().job_mark_partner_for_export(record.pricelist_id.id)
else:
# self.env['product.pricelist.item'].with_delay().job_export_portal_pricelist(record.pricelist_id.id)
self.env['product.pricelist.item'].job_export_portal_pricelist(record.pricelist_id.id)
class ProductPricelistItem(models.Model):
_inherit = 'product.pricelist.item'
applied_on = fields.Selection(selection=[
('3_global', 'Global'),
('2_product_category', ' Product Category'),
('0_product_variant', 'Product Variant')])
@api.multi
@job
def job_mark_partner_for_export(self, pricelist_id):
partners = self.env['res.partner'].search([('portal_id', '!=', False)])
todo_partner = self.env['res.partner']
for partner in partners:
# Search ist auf die Preisliste nicht möglich, daher wird jeder Partner einzeln verglichen
if partner.property_product_pricelist.id == pricelist_id and partner.company_type == 'company':
todo_partner |= partner
todo_partner.write({
'portal_export_pending': True
})
@api.multi
@job
def job_export_portal_pricelist(self, pricelist_id):
"""
SST-02a
:param pricelist_id:
:return:
"""
pricelist = self.env['product.pricelist'].search([('id', '=', pricelist_id)])
data_pos = []
for item in pricelist.item_ids:
if item.compute_price == 'percentage' and item.applied_on in ['3_global', '2_product_category',
'0_product_variant']:
code = False
if item.applied_on == '2_product_category':
code = item.categ_id.code
if item.applied_on == '0_product_variant':
code = item.product_id.product_tmpl_id.default_code
data_pos.append({
'code': code,
'name': item.name,
'discount': 1 - (item.percent_price / 100)
})
if data_pos:
data = {'pricelist_id': pricelist.id,
'pricelist_name': pricelist.name,
'items': data_pos}
portal_url = tools.config.get('portal_url')
application_id = tools.config.get('portal_secret')
response = requests.post(portal_url + '/api/v1/update-pricelist/?secret=' + application_id,
data=json.dumps(data))
if response.status_code != 200:
try:
data = response.json()
error_string = data.get('errors', [])
except:
error_string = response.reason
raise ValidationError(_('Meldung vom Portal: Rabatt konnte nicht gesetzt werden. '
'Status Code: %s, Reason: %s') % (response.status_code, error_string))