278 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			278 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 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'])])
 | |
|         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)
 | |
|         else:
 | |
|             if vals['active']:
 | |
|                 self.create(vals)
 | |
|         return True
 | |
| 
 | |
|     @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))
 | |
| 
 |