class HrPayslipLine(models.Model): _name = 'hr.payslip.line' _inherit = 'hr.salary.rule' _description = 'Payslip Line' _order = 'contract_id, sequence' slip_id = fields.Many2one('hr.payslip', string='Pay Slip', required=True, ondelete='cascade') salary_rule_id = fields.Many2one('hr.salary.rule', string='Rule', required=True) employee_id = fields.Many2one('hr.employee', string='Employee', required=True) contract_id = fields.Many2one('hr.contract', string='Contract', required=True, index=True) rate = fields.Float(string='Rate (%)', digits=dp.get_precision('Payroll Rate'), default=100.0) amount = fields.Float(digits=dp.get_precision('Payroll')) quantity = fields.Float(digits=dp.get_precision('Payroll'), default=1.0) total = fields.Monetary(compute='_compute_total', string='Total', digits=dp.get_precision('Payroll'), store=True, currency_field='company_currency_id') company_currency_id = fields.Many2one( 'res.currency', related='employee_id.company_id.currency_id', string="Company Currency", readonly=True) @api.depends('quantity', 'amount', 'rate') def _compute_total(self): for line in self: line.total = float(line.quantity) * line.amount * line.rate / 100 @api.model def create(self, values): if 'employee_id' not in values or 'contract_id' not in values: payslip = self.env['hr.payslip'].browse(values.get('slip_id')) values['employee_id'] = values.get('employee_id') or payslip.employee_id.id values['contract_id'] = values.get('contract_id') or payslip.contract_id and payslip.contract_id.id if not values['contract_id']: raise UserError(_('You must set a contract to create a payslip line.')) return super(HrPayslipLine, self).create(values)
class report_account_analytic_line_to_invoice(models.Model): _name = "report.account.analytic.line.to.invoice" _description = "Analytic lines to invoice report" _order = 'name desc, product_id asc, account_id asc' _auto = False name = fields.Char(string='Year', readonly=True) product_id = fields.Many2one('product.product', string='Product', readonly=True) account_id = fields.Many2one('account.analytic.account', string='Analytic account', readonly=True) product_uom_id = fields.Many2one('product.uom', string='Unit of Measure', readonly=True) unit_amount = fields.Float(string='Units', readonly=True) sale_price = fields.Float(string='Sale price', readonly=True, digits=dp.get_precision('Product Price')) amount = fields.Float(string='Amount', readonly=True, digits=dp.get_precision('Account')) month = fields.Selection([('01', 'January'), ('02', 'February'), ('03', 'March'), ('04', 'April'), ('05', 'May'), ('06', 'June'), ('07', 'July'), ('08', 'August'), ('09', 'September'), ('10', 'October'), ('11', 'November'), ('12', 'December')], string='Month', readonly=True) @api.model_cr def init(self): cr = self._cr drop_view_if_exists(cr, 'report_account_analytic_line_to_invoice') cr.execute(""" CREATE OR REPLACE VIEW report_account_analytic_line_to_invoice AS ( SELECT DISTINCT(to_char(l.date,'MM')) as month, to_char(l.date, 'YYYY') as name, MIN(l.id) AS id, l.product_id, l.account_id, SUM(l.amount) AS amount, SUM(l.unit_amount * t.list_price) AS sale_price, SUM(l.unit_amount) AS unit_amount, l.product_uom_id FROM account_analytic_line l left join product_product p on (l.product_id=p.id) left join product_template t on (p.product_tmpl_id=t.id) WHERE (invoice_id IS NULL) and (to_invoice IS NOT NULL) GROUP BY to_char(l.date, 'YYYY'), to_char(l.date,'MM'), l.product_id, l.product_uom_id, l.account_id ) """)
class PriceRule(models.Model): _name = "delivery.price.rule" _description = "Delivery Price Rules" _order = 'sequence, list_price, id' @api.depends('variable', 'operator', 'max_value', 'list_base_price', 'list_price', 'variable_factor') def _compute_name(self): for rule in self: name = 'if %s %s %s then' % (rule.variable, rule.operator, rule.max_value) if rule.list_base_price and not rule.list_price: name = '%s fixed price %s' % (name, rule.list_base_price) elif rule.list_price and not rule.list_base_price: name = '%s %s times %s' % (name, rule.list_price, rule.variable_factor) else: name = '%s fixed price %s plus %s times %s' % (name, rule.list_base_price, rule.list_price, rule.variable_factor) rule.name = name name = fields.Char(compute='_compute_name') sequence = fields.Integer(required=True, default=10) carrier_id = fields.Many2one('delivery.carrier', 'Carrier', required=True, ondelete='cascade') variable = fields.Selection([('weight', 'Weight'), ('volume', 'Volume'), ('wv', 'Weight * Volume'), ('price', 'Price'), ('quantity', 'Quantity')], required=True, default='weight') operator = fields.Selection([('==', '='), ('<=', '<='), ('<', '<'), ('>=', '>='), ('>', '>')], required=True, default='<=') max_value = fields.Float('Maximum Value', required=True) list_base_price = fields.Float(string='Sale Base Price', digits=dp.get_precision('Product Price'), required=True, default=0.0) list_price = fields.Float('Sale Price', digits=dp.get_precision('Product Price'), required=True, default=0.0) variable_factor = fields.Selection([('weight', 'Weight'), ('volume', 'Volume'), ('wv', 'Weight * Volume'), ('price', 'Price'), ('quantity', 'Quantity')], 'Variable Factor', required=True, default='weight')
class HrContract(models.Model): """ Employee contract allows to add different values in fields. Fields are used in salary rule computation. """ _inherit = 'hr.contract' tds = fields.Float(string='TDS', digits=dp.get_precision('Payroll'), help='Amount for Tax Deduction at Source') driver_salay = fields.Boolean( string='Driver Salary', help='Check this box if you provide allowance for driver') medical_insurance = fields.Float( string='Medical Insurance', digits=dp.get_precision('Payroll'), help='Deduction towards company provided medical insurance') voluntary_provident_fund = fields.Float( string='Voluntary Provident Fund (%)', digits=dp.get_precision('Payroll'), help= 'VPF is a safe option wherein you can contribute more than the PF ceiling of 12% that has been mandated by the government and VPF computed as percentage(%)' ) house_rent_allowance_metro_nonmetro = fields.Float( string='House Rent Allowance (%)', digits=dp.get_precision('Payroll'), help= 'HRA is an allowance given by the employer to the employee for taking care of his rental or accommodation expenses for metro city it is 50% and for non metro 40%. \nHRA computed as percentage(%)' ) supplementary_allowance = fields.Float(string='Supplementary Allowance', digits=dp.get_precision('Payroll'))
class Product(models.Model): _inherit = "product.product" def _get_default_website_ids(self): default_website_id = self.env.ref('website.default_website') return [default_website_id.id] if default_website_id else None website_ids = fields.Many2many('website', string="Publish Product On Website", default=_get_default_website_ids) website_price = fields.Float('Website price', compute='_website_price', digits=dp.get_precision('Product Price')) website_public_price = fields.Float( 'Website public price', compute='_website_price', digits=dp.get_precision('Product Price')) website_price_difference = fields.Boolean('Website price difference', compute='_website_price') def _website_price(self): qty = self._context.get('quantity', 1.0) partner = self.env.user.partner_id current_website = self.env['website'].get_current_website() pricelist = current_website.get_current_pricelist() company_id = current_website.company_id context = dict(self._context, pricelist=pricelist.id, partner=partner) self2 = self.with_context( context) if self._context != context else self ret = self.env.user.has_group( 'sale.group_show_price_subtotal' ) and 'total_excluded' or 'total_included' for p, p2 in pycompat.izip(self, self2): taxes = partner.property_account_position_id.map_tax( p.sudo().taxes_id.filtered( lambda x: x.company_id == company_id)) p.website_price = taxes.compute_all(p2.price, pricelist.currency_id, quantity=qty, product=p2, partner=partner)[ret] price_without_pricelist = taxes.compute_all( p.list_price, pricelist.currency_id)[ret] p.website_price_difference = False if float_is_zero( price_without_pricelist - p.website_price, precision_rounding=pricelist.currency_id.rounding) else True p.website_public_price = taxes.compute_all(p2.lst_price, quantity=qty, product=p2, partner=partner)[ret] @api.multi def website_publish_button(self): self.ensure_one() return self.product_tmpl_id.website_publish_button()
class SaleQuoteOption(models.Model): _name = "sale.quote.option" _description = "Quotation Option" template_id = fields.Many2one('sale.quote.template', 'Quotation Template Reference', ondelete='cascade', index=True, required=True) name = fields.Text('Description', required=True, translate=True) product_id = fields.Many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], required=True) layout_category_id = fields.Many2one('sale.layout_category', string='Section') website_description = fields.Html('Option Description', translate=html_translate, sanitize_attributes=False) price_unit = fields.Float('Unit Price', required=True, digits=dp.get_precision('Product Price')) discount = fields.Float('Discount (%)', digits=dp.get_precision('Discount')) uom_id = fields.Many2one('product.uom', 'Unit of Measure ', required=True) quantity = fields.Float('Quantity', required=True, digits=dp.get_precision('Product UoS'), default=1) @api.onchange('product_id') def _onchange_product_id(self): if not self.product_id: return product = self.product_id self.price_unit = product.list_price self.website_description = product.product_tmpl_id.quote_description name = product.name if self.product_id.description_sale: name += '\n' + self.product_id.description_sale self.name = name self.uom_id = product.uom_id domain = { 'uom_id': [('category_id', '=', self.product_id.uom_id.category_id.id)] } return {'domain': domain} @api.onchange('uom_id') def _onchange_product_uom(self): if not self.product_id: return if not self.uom_id: self.price_unit = 0.0 return if self.uom_id.id != self.product_id.uom_id.id: self.price_unit = self.product_id.uom_id._compute_price( self.price_unit, self.uom_id)
class SaleQuoteLine(models.Model): _name = "sale.quote.line" _description = "Quotation Template Lines" _order = 'sequence, id' sequence = fields.Integer('Sequence', help="Gives the sequence order when displaying a list of sale quote lines.", default=10) quote_id = fields.Many2one('sale.quote.template', 'Quotation Template Reference', required=True, ondelete='cascade', index=True) name = fields.Text('Description', required=True, translate=True) product_id = fields.Many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], required=True) layout_category_id = fields.Many2one('sale.layout_category', string='Section') website_description = fields.Html('Line Description', related='product_id.product_tmpl_id.quote_description', translate=html_translate) price_unit = fields.Float('Unit Price', required=True, digits=dp.get_precision('Product Price')) discount = fields.Float('Discount (%)', digits=dp.get_precision('Discount'), default=0.0) product_uom_qty = fields.Float('Quantity', required=True, digits=dp.get_precision('Product UoS'), default=1) product_uom_id = fields.Many2one('product.uom', 'Unit of Measure ', required=True) @api.onchange('product_id') def _onchange_product_id(self): self.ensure_one() if self.product_id: name = self.product_id.name_get()[0][1] if self.product_id.description_sale: name += '\n' + self.product_id.description_sale self.name = name self.price_unit = self.product_id.lst_price self.product_uom_id = self.product_id.uom_id.id self.website_description = self.product_id.quote_description or self.product_id.website_description or '' domain = {'product_uom_id': [('category_id', '=', self.product_id.uom_id.category_id.id)]} return {'domain': domain} @api.onchange('product_uom_id') def _onchange_product_uom(self): if self.product_id and self.product_uom_id: self.price_unit = self.product_id.uom_id._compute_price(self.product_id.lst_price, self.product_uom_id) @api.model def create(self, values): values = self._inject_quote_description(values) return super(SaleQuoteLine, self).create(values) @api.multi def write(self, values): values = self._inject_quote_description(values) return super(SaleQuoteLine, self).write(values) def _inject_quote_description(self, values): values = dict(values or {}) if not values.get('website_description') and values.get('product_id'): product = self.env['product.product'].browse(values['product_id']) values['website_description'] = product.quote_description or product.website_description or '' return values
class PurchaseRequisitionLine(models.Model): _name = "purchase.requisition.line" _description = "Purchase Requisition Line" _rec_name = 'product_id' product_id = fields.Many2one('product.product', string='Product', domain=[('purchase_ok', '=', True)], required=True) product_uom_id = fields.Many2one('product.uom', string='Product Unit of Measure') product_qty = fields.Float(string='Quantity', digits=dp.get_precision('Product Unit of Measure')) price_unit = fields.Float(string='Unit Price', digits=dp.get_precision('Product Price')) qty_ordered = fields.Float(compute='_compute_ordered_qty', string='Ordered Quantities') requisition_id = fields.Many2one('purchase.requisition', string='Purchase Agreement', ondelete='cascade') company_id = fields.Many2one('res.company', related='requisition_id.company_id', string='Company', store=True, readonly=True, default= lambda self: self.env['res.company']._company_default_get('purchase.requisition.line')) account_analytic_id = fields.Many2one('account.analytic.account', string='Analytic Account') schedule_date = fields.Date(string='Scheduled Date') move_dest_id = fields.Many2one('stock.move', 'Downstream Move') @api.multi @api.depends('requisition_id.purchase_ids.state') def _compute_ordered_qty(self): for line in self: total = 0.0 for po in line.requisition_id.purchase_ids.filtered(lambda purchase_order: purchase_order.state in ['purchase', 'done']): for po_line in po.order_line.filtered(lambda order_line: order_line.product_id == line.product_id): if po_line.product_uom != line.product_uom_id: total += po_line.product_uom._compute_quantity(po_line.product_qty, line.product_uom_id) else: total += po_line.product_qty line.qty_ordered = total @api.onchange('product_id') def _onchange_product_id(self): if self.product_id: self.product_uom_id = self.product_id.uom_id self.product_qty = 1.0 if not self.account_analytic_id: self.account_analytic_id = self.requisition_id.account_analytic_id if not self.schedule_date: self.schedule_date = self.requisition_id.schedule_date @api.multi def _prepare_purchase_order_line(self, name, product_qty=0.0, price_unit=0.0, taxes_ids=False): self.ensure_one() requisition = self.requisition_id return { 'name': name, 'product_id': self.product_id.id, 'product_uom': self.product_id.uom_po_id.id, 'product_qty': product_qty, 'price_unit': price_unit, 'taxes_id': [(6, 0, taxes_ids)], 'date_planned': requisition.schedule_date or fields.Date.today(), 'account_analytic_id': self.account_analytic_id.id, 'move_dest_ids': self.move_dest_id and [(4, self.move_dest_id.id)] or [] }
class PurchaseOrderLine(models.Model): _inherit = "purchase.order.line" @api.depends('discount2', 'discount3') def _compute_amount(self): super(PurchaseOrderLine, self)._compute_amount() discount2 = fields.Float( 'Disc. 2 (%)', digits=dp.get_precision('Discount'), ) discount3 = fields.Float( 'Disc. 3 (%)', digits=dp.get_precision('Discount'), ) _sql_constraints = [ ('discount2_limit', 'CHECK (discount2 <= 100.0)', 'Discount 2 must be lower than 100%.'), ('discount3_limit', 'CHECK (discount3 <= 100.0)', 'Discount 3 must be lower than 100%.'), ] def _get_discounted_price_unit(self): price_unit = super(PurchaseOrderLine, self)._get_discounted_price_unit() if self.discount2: price_unit *= (1 - self.discount2 / 100.0) if self.discount3: price_unit *= (1 - self.discount3 / 100.0) return price_unit @api.onchange('product_qty', 'product_uom') def _onchange_quantity(self): """ Check if a discount is defined into the supplier info and if so then apply it to the current purchase order line """ res = super(PurchaseOrderLine, self)._onchange_quantity() if self.product_id: date = None if self.order_id.date_order: date = fields.Date.to_string( fields.Date.from_string(self.order_id.date_order)) product_supplierinfo = self.product_id._select_seller( partner_id=self.partner_id, quantity=self.product_qty, date=date, uom_id=self.product_uom) if product_supplierinfo: self.discount2 = product_supplierinfo.discount2 self.discount3 = product_supplierinfo.discount3 return res
class ResCompany(models.Model): _inherit = 'res.company' plafond_secu = fields.Float(string='Plafond de la Securite Sociale', digits=dp.get_precision('Payroll')) nombre_employes = fields.Integer(string='Nombre d\'employes') cotisation_prevoyance = fields.Float( string='Cotisation Patronale Prevoyance', digits=dp.get_precision('Payroll')) org_ss = fields.Char(string='Organisme de securite sociale') conv_coll = fields.Char(string='Convention collective')
class WizIndentLine(models.TransientModel): _name = 'wiz.indent.line' _description = "Wizard Indent Line" @api.depends('purchase_indent_line_id', 'purchase_indent_line_id.product_qty', 'purchase_indent_line_id.requisition_qty') @api.multi def _compute_get_rem_qty(self): for line_id in self: remaining_qty = 0.0 if line_id.purchase_indent_line_id: remaining_qty = \ line_id.purchase_indent_line_id.product_qty - \ line_id.purchase_indent_line_id.requisition_qty line_id.remaining_qty = remaining_qty purchase_indent_ids = fields.Many2many( 'purchase.indent', string='Purchase Indent') name = fields.Text(string='Description', required=True) sequence = fields.Integer(string='Sequence', default=10) product_qty = fields.Float( string='Quantity', digits=dp.get_precision('Discount')) expected_date = fields.Datetime(string='Expected Date', index=True) product_uom = fields.Many2one( 'product.uom', string='Product Unit of Measure') product_id = fields.Many2one( 'product.product', string='Product', domain=[('purchase_ok', '=', True)], change_default=True, required=True) requisition_qty = fields.Float( string="Requisition Quantity", digits=dp.get_precision('Discount')) wizard_indent_id = fields.Many2one( 'wiz.requisition.request', 'Wiz Requisition Request') partner_id = fields.Many2one('res.partner', string='Partner') price_unit = fields.Float( string='Unit Price', digits=dp.get_precision('Product Price')) taxes_id = fields.Many2many( 'account.tax', string='Taxes', domain=['|', ('active', '=', False), ('active', '=', True)]) purchase_indent_line_id = fields.Many2one( 'purchase.indent.line', string="Indent Line Ref") remaining_qty = fields.Float( compute='_compute_get_rem_qty', string='Remaining Quantity', store=True) order_type = fields.Selection( related='wizard_indent_id.order_type', string='Order Type')
class ResPartner(models.Model): _inherit = "res.partner" default_supplierinfo_discount2 = fields.Float( string='Default Supplier Discount 2 (%)', digits=dp.get_precision('Discount'), help="This value will be used as the default one, for each new " "supplierinfo line depending on that supplier.", ) default_supplierinfo_discount3 = fields.Float( string='Default Supplier Discount 3 (%)', digits=dp.get_precision('Discount'), help="This value will be used as the default one, for each new " "supplierinfo line depending on that supplier.", )
class PurchaseCostDistributionLineExpense(models.Model): _name = "purchase.cost.distribution.line.expense" _description = "Purchase cost distribution line expense" distribution_line = fields.Many2one( comodel_name='purchase.cost.distribution.line', string='Cost distribution line', ondelete="cascade", ) picking_id = fields.Many2one( comodel_name="stock.picking", store=True, readonly=True, related="distribution_line.picking_id", ) picking_date_done = fields.Datetime( related="picking_id.date_done", store=True, readonly=True, ) distribution_expense = fields.Many2one( comodel_name='purchase.cost.distribution.expense', string='Distribution expense', ondelete="cascade", ) type = fields.Many2one( 'purchase.expense.type', string='Expense type', readonly=True, related='distribution_expense.type', store=True, ) expense_amount = fields.Float( string='Expense amount', digits=dp.get_precision('Account'), ) cost_ratio = fields.Float('Unit cost') company_id = fields.Many2one( comodel_name="res.company", related="distribution_line.company_id", store=True, readonly=True, )
class MembershipInvoice(models.TransientModel): _name = "membership.invoice" _description = "Membership Invoice" product_id = fields.Many2one('product.product', string='Membership', required=True) member_price = fields.Float(string='Member Price', digits= dp.get_precision('Product Price'), required=True) @api.onchange('product_id') def onchange_product(self): """This function returns value of product's member price based on product id. """ price_dict = self.product_id.price_compute('list_price') self.member_price = price_dict.get(self.product_id.id) or False @api.multi def membership_invoice(self): if self: datas = { 'membership_product_id': self.product_id.id, 'amount': self.member_price } invoice_list = self.env['res.partner'].browse(self._context.get('active_ids')).create_membership_invoice(datas=datas) search_view_ref = self.env.ref('account.view_account_invoice_filter', False) form_view_ref = self.env.ref('account.invoice_form', False) tree_view_ref = self.env.ref('account.invoice_tree', False) return { 'domain': [('id', 'in', invoice_list)], 'name': 'Membership Invoices', 'res_model': 'account.invoice', 'type': 'ir.actions.act_window', 'views': [(tree_view_ref.id, 'tree'), (form_view_ref.id, 'form')], 'search_view_id': search_view_ref and search_view_ref.id, }
class LandedCostLine(models.Model): _name = 'stock.landed.cost.lines' _description = 'Stock Landed Cost Lines' name = fields.Char('Description') cost_id = fields.Many2one('stock.landed.cost', 'Landed Cost', required=True, ondelete='cascade') product_id = fields.Many2one('product.product', 'Product', required=True) price_unit = fields.Float('Cost', digits=dp.get_precision('Product Price'), required=True) split_method = fields.Selection(product.SPLIT_METHOD, string='Split Method', required=True) account_id = fields.Many2one('account.account', 'Account', domain=[('deprecated', '=', False)]) @api.onchange('product_id') def onchange_product_id(self): if not self.product_id: self.quantity = 0.0 self.name = self.product_id.name or '' self.split_method = self.product_id.split_method or 'equal' self.price_unit = self.product_id.standard_price or 0.0 self.account_id = self.product_id.property_account_expense_id.id or self.product_id.categ_id.property_account_expense_categ_id.id
class HrPayrollAdviceLine(models.Model): ''' Bank Advice Lines ''' _name = 'hr.payroll.advice.line' _description = 'Bank Advice Lines' advice_id = fields.Many2one('hr.payroll.advice', string='Bank Advice') name = fields.Char('Bank Account No.', required=True) ifsc_code = fields.Char(string='IFSC Code') employee_id = fields.Many2one('hr.employee', string='Employee', required=True) bysal = fields.Float(string='By Salary', digits=dp.get_precision('Payroll')) debit_credit = fields.Char(string='C/D', default='C') company_id = fields.Many2one('res.company', related='advice_id.company_id', string='Company', store=True) ifsc = fields.Boolean(related='advice_id.neft', string='IFSC') @api.onchange('employee_id') def onchange_employee_id(self): self.name = self.employee_id.bank_account_id.acc_number self.ifsc_code = self.employee_id.bank_account_id.bank_bic or ''
class StockMove(models.Model): _inherit = 'stock.move' def _default_uom(self): uom_categ_id = self.env.ref('product.product_uom_categ_kgm').id return self.env['product.uom'].search( [('category_id', '=', uom_categ_id), ('factor', '=', 1)], limit=1) weight = fields.Float(compute='_cal_move_weight', digits=dp.get_precision('Stock Weight'), store=True) weight_uom_id = fields.Many2one( 'product.uom', string='Weight Unit of Measure', required=True, readonly=True, help= "Unit of Measure (Unit of Measure) is the unit of measurement for Weight", default=_default_uom) @api.depends('product_id', 'product_uom_qty', 'product_uom') def _cal_move_weight(self): for move in self.filtered( lambda moves: moves.product_id.weight > 0.00): move.weight = (move.product_qty * move.product_id.weight) def _get_new_picking_values(self): vals = super(StockMove, self)._get_new_picking_values() vals['carrier_id'] = self.sale_line_id.order_id.carrier_id.id return vals
class MrpSubProduct(models.Model): _name = 'mrp.subproduct' _description = 'Byproduct' product_id = fields.Many2one('product.product', 'Product', required=True) product_qty = fields.Float( 'Product Qty', default=1.0, digits=dp.get_precision('Product Unit of Measure'), required=True) product_uom_id = fields.Many2one('product.uom', 'Unit of Measure', required=True) bom_id = fields.Many2one('mrp.bom', 'BoM', ondelete='cascade') operation_id = fields.Many2one('mrp.routing.workcenter', 'Produced at Operation') @api.onchange('product_id') def onchange_product_id(self): """ Changes UoM if product_id changes. """ if self.product_id: self.product_uom_id = self.product_id.uom_id.id @api.onchange('product_uom_id') def onchange_uom(self): res = {} if self.product_uom_id and self.product_id and self.product_uom_id.category_id != self.product_id.uom_id.category_id: res['warning'] = { 'title': _('Warning'), 'message': _('The Product Unit of Measure you chose has a different category than in the product form.') } self.product_uom_id = self.product_id.uom_id.id return res
class PurchaseOrderRecommendationLine(models.TransientModel): _inherit = 'purchase.order.recommendation.line' secondary_uom_id = fields.Many2one( comodel_name='product.secondary.unit', related='product_id.purchase_secondary_uom_id', readonly=True, ) secondary_uom_qty = fields.Float( string='Secondary Qty', digits=dp.get_precision('Product Unit of Measure'), ) @api.onchange('secondary_uom_id', 'secondary_uom_qty') def _onchange_secondary_uom(self): if not self.secondary_uom_id: return factor = self.secondary_uom_id.factor * self.product_id.uom_id.factor qty = float_round(self.secondary_uom_qty * factor, precision_rounding=self.product_id.uom_id.rounding) if float_compare( self.units_included, qty, precision_rounding=self.product_id.uom_id.rounding) != 0: self.units_included = qty @api.onchange('units_included') def _onchange_units_included_purchase_order_secondary_unit(self): if not self.secondary_uom_id: return factor = self.secondary_uom_id.factor * self.product_id.uom_id.factor qty = float_round( self.units_included / (factor or 1.0), precision_rounding=self.secondary_uom_id.uom_id.rounding) if float_compare( self.secondary_uom_qty, qty, precision_rounding=self.secondary_uom_id.uom_id.rounding) != 0: self.secondary_uom_qty = qty @api.multi def _prepare_update_po_line(self): res = super()._prepare_update_po_line() if self.secondary_uom_id and self.secondary_uom_qty: res.update({ 'secondary_uom_id': self.secondary_uom_id.id, 'secondary_uom_qty': self.secondary_uom_qty, }) return res @api.multi def _prepare_new_po_line(self, sequence): res = super()._prepare_new_po_line(sequence) if self.secondary_uom_id and self.secondary_uom_qty: res.update({ 'secondary_uom_id': self.secondary_uom_id.id, 'secondary_uom_qty': self.secondary_uom_qty, }) return res
class ProductAttributevalue(models.Model): _name = "product.attribute.value" _order = 'sequence, attribute_id, id' name = fields.Char('Value', required=True, translate=True) sequence = fields.Integer('Sequence', help="Determine the display order") attribute_id = fields.Many2one('product.attribute', 'Attribute', ondelete='cascade', required=True) product_ids = fields.Many2many('product.product', string='Variants', readonly=True) price_extra = fields.Float( 'Attribute Price Extra', compute='_compute_price_extra', inverse='_set_price_extra', default=0.0, digits=dp.get_precision('Product Price'), help="Price Extra: Extra price for the variant with this attribute value on sale price. eg. 200 price extra, 1000 + 200 = 1200.") price_ids = fields.One2many('product.attribute.price', 'value_id', 'Attribute Prices', readonly=True) _sql_constraints = [ ('value_company_uniq', 'unique (name,attribute_id)', 'This attribute value already exists !') ] @api.one def _compute_price_extra(self): if self._context.get('active_id'): price = self.price_ids.filtered(lambda price: price.product_tmpl_id.id == self._context['active_id']) self.price_extra = price.price_extra else: self.price_extra = 0.0 def _set_price_extra(self): if not self._context.get('active_id'): return AttributePrice = self.env['product.attribute.price'] prices = AttributePrice.search([('value_id', 'in', self.ids), ('product_tmpl_id', '=', self._context['active_id'])]) updated = prices.mapped('value_id') if prices: prices.write({'price_extra': self.price_extra}) else: for value in self - updated: AttributePrice.create({ 'product_tmpl_id': self._context['active_id'], 'value_id': value.id, 'price_extra': self.price_extra, }) @api.multi def name_get(self): if not self._context.get('show_attribute', True): # TDE FIXME: not used return super(ProductAttributevalue, self).name_get() return [(value.id, "%s: %s" % (value.attribute_id.name, value.name)) for value in self] @api.multi def unlink(self): linked_products = self.env['product.product'].with_context(active_test=False).search([('attribute_value_ids', 'in', self.ids)]) if linked_products: raise UserError(_('The operation cannot be completed:\nYou are trying to delete an attribute value with a reference on a product variant.')) return super(ProductAttributevalue, self).unlink() @api.multi def _variant_name(self, variable_attributes): return ", ".join([v.name for v in self if v.attribute_id in variable_attributes])
class PurchaseOrderLine(models.Model): _inherit = 'purchase.order.line' @api.depends('product_qty', 'qty_invoiced', 'invoice_lines.invoice_id.state', 'order_id.state', 'order_id.invoice_status', 'move_ids.state', 'qty_received') def _compute_qty_to_invoice(self): for line in self: # If the invoice status has been forced to invoiced, # then respect it. See module purchase_force_invoiced. if getattr(line.order_id, 'force_invoiced', None): line.qty_to_invoice = 0.0 elif line.product_id.purchase_method == 'receive': qty = line.qty_received - line.qty_invoiced if qty >= 0.0: line.qty_to_invoice = qty else: line.qty_to_invoice = 0.0 else: line.qty_to_invoice = line.product_qty - line.qty_invoiced @api.depends('order_id.state', 'move_ids.state', 'product_qty') def _compute_qty_to_receive(self): for line in self: total = 0.0 for move in line.move_ids.filtered(lambda m: m.state not in ('cancel', 'done')): if move.product_uom != line.product_uom: total += move.product_uom._compute_quantity( move.product_uom_qty, line.product_uom) else: total += move.product_uom_qty line.qty_to_receive = total qty_to_invoice = fields.Float( compute='_compute_qty_to_invoice', digits=dp.get_precision('Product Unit of Measure'), copy=False, string="Qty to Bill", store=True) qty_to_receive = fields.Float( compute='_compute_qty_to_receive', digits=dp.get_precision('Product Unit of Measure'), copy=False, string="Qty to Receive", store=True)
class ResPartner(models.Model): _inherit = 'res.partner' purchase_general_discount = fields.Float( digits=dp.get_precision('Discount'), string='Purchase General Discount (%)', company_dependent=True, )
class PurchaseOrderLine(models.Model): _inherit = 'purchase.order.line' secondary_uom_qty = fields.Float( string='Secondary Qty', digits=dp.get_precision('Product Unit of Measure'), ) secondary_uom_id = fields.Many2one( comodel_name='product.secondary.unit', string='Secondary uom', ondelete='restrict', ) @api.onchange('secondary_uom_id', 'secondary_uom_qty') def _onchange_secondary_uom(self): if not self.secondary_uom_id: return factor = self.secondary_uom_id.factor * self.product_uom.factor qty = float_round( self.secondary_uom_qty * factor, precision_rounding=self.product_uom.rounding ) if float_compare( self.product_qty, qty, precision_rounding=self.product_uom.rounding) != 0: self.product_qty = qty @api.onchange('product_qty') def _onchange_product_qty_purchase_order_secondary_unit(self): if not self.secondary_uom_id: return factor = self.secondary_uom_id.factor * self.product_uom.factor qty = float_round( self.product_qty / (factor or 1.0), precision_rounding=self.secondary_uom_id.uom_id.rounding ) if float_compare( self.secondary_uom_qty, qty, precision_rounding=self.secondary_uom_id.uom_id.rounding) != 0: self.secondary_uom_qty = qty @api.onchange('product_uom') def _onchange_product_uom_purchase_order_secondary_unit(self): if not self.secondary_uom_id: return factor = self.product_uom.factor * self.secondary_uom_id.factor qty = float_round( self.product_qty / (factor or 1.0), precision_rounding=self.product_uom.rounding ) if float_compare( self.secondary_uom_qty, qty, precision_rounding=self.product_uom.rounding) != 0: self.secondary_uom_qty = qty @api.onchange('product_id') def _onchange_product_id_purchase_order_secondary_unit(self): self.secondary_uom_id = self.product_id.purchase_secondary_uom_id
class MRPSimpleLine(models.TransientModel): _name = 'mrp.simple.line' mrp_simple_id = fields.Many2one('mrp.simple') product_id = fields.Many2one('product.product') quantity = fields.Float(string="Quantity", digits=dp.get_precision('Product Unit of Measure'), default=1) price_unit = fields.Float('Unit Price', digits=dp.get_precision('Product Price')) uom_id = fields.Many2one('product.uom', 'Unit of Measure') type = fields.Selection([('consumption', 'Consumption in production'), ('receipt', 'Receipt from production')], string='Type') @api.onchange('product_id') def onchange_product_id(self): self.uom_id = self.product_id.uom_id
class QcTestQuestion(models.Model): """Each test line is a question with its valid value(s).""" _name = 'qc.test.question' _description = 'Quality control question' _order = 'sequence, id' @api.constrains('ql_values') def _check_valid_answers(self): for tc in self: if (tc.type == 'qualitative' and tc.ql_values and not tc.ql_values.filtered('ok')): raise exceptions.ValidationError( _("Question '%s' is not valid: " "you have to mark at least one value as OK.") % tc.name_get()[0][1]) @api.constrains('min_value', 'max_value') def _check_valid_range(self): for tc in self: if tc.type == 'quantitative' and tc.min_value > tc.max_value: raise exceptions.ValidationError( _("Question '%s' is not valid: " "minimum value can't be higher than maximum value.") % tc.name_get()[0][1]) sequence = fields.Integer(string='Sequence', required=True, default="10") test = fields.Many2one(comodel_name='qc.test', string='Test') name = fields.Char(string='Name', required=True, translate=True) type = fields.Selection([('qualitative', 'Qualitative'), ('quantitative', 'Quantitative')], string='Type', required=True) ql_values = fields.One2many(comodel_name='qc.test.question.value', inverse_name="test_line", string='Qualitative values', copy=True) notes = fields.Text(string='Notes') min_value = fields.Float(string='Min', digits=dp.get_precision('Quality Control')) max_value = fields.Float( string='Max', digits=dp.get_precision('Quality Control'), ) uom_id = fields.Many2one(comodel_name='product.uom', string='Uom')
class MrpProductProduceLine(models.TransientModel): _name = "mrp.product.produce.line" _description = "Record Production Line" product_produce_id = fields.Many2one('mrp.product.produce') product_id = fields.Many2one('product.product', 'Product') lot_id = fields.Many2one('stock.production.lot', 'Lot') qty_to_consume = fields.Float( 'To Consume', digits=dp.get_precision('Product Unit of Measure')) product_uom_id = fields.Many2one('product.uom', 'Unit of Measure') qty_done = fields.Float('Done', digits=dp.get_precision('Product Unit of Measure')) move_id = fields.Many2one('stock.move') @api.onchange('lot_id') def _onchange_lot_id(self): """ When the user is encoding a produce line for a tracked product, we apply some logic to help him. This onchange will automatically switch `qty_done` to 1.0. """ res = {} if self.product_id.tracking == 'serial': self.qty_done = 1 return res @api.onchange('qty_done') def _onchange_qty_done(self): """ When the user is encoding a produce line for a tracked product, we apply some logic to help him. This onchange will warn him if he set `qty_done` to a non-supported value. """ res = {} if self.product_id.tracking == 'serial': if float_compare(self.qty_done, 1.0, precision_rounding=self.move_id.product_id.uom_id. rounding) != 0: message = _( 'You can only process 1.0 %s for products with unique serial number.' ) % self.product_id.uom_id.name res['warning'] = {'title': _('Warning'), 'message': message} return res @api.onchange('product_id') def _onchange_product_id(self): self.product_uom_id = self.product_id.uom_id.id
class RepairFee(models.Model): _name = 'mrp.repair.fee' _description = 'Repair Fees Line' repair_id = fields.Many2one( 'mrp.repair', 'Repair Order Reference', index=True, ondelete='cascade', required=True) name = fields.Char('Description', index=True, required=True) product_id = fields.Many2one('product.product', 'Product') product_uom_qty = fields.Float('Quantity', digits=dp.get_precision('Product Unit of Measure'), required=True, default=1.0) price_unit = fields.Float('Unit Price', required=True) product_uom = fields.Many2one('product.uom', 'Product Unit of Measure', required=True) price_subtotal = fields.Float('Subtotal', compute='_compute_price_subtotal', digits=0) tax_id = fields.Many2many('account.tax', 'repair_fee_line_tax', 'repair_fee_line_id', 'tax_id', 'Taxes') invoice_line_id = fields.Many2one('account.invoice.line', 'Invoice Line', copy=False, readonly=True) invoiced = fields.Boolean('Invoiced', copy=False, readonly=True) @api.one @api.depends('price_unit', 'repair_id', 'product_uom_qty', 'product_id') def _compute_price_subtotal(self): taxes = self.tax_id.compute_all(self.price_unit, self.repair_id.pricelist_id.currency_id, self.product_uom_qty, self.product_id, self.repair_id.partner_id) self.price_subtotal = taxes['total_excluded'] @api.onchange('repair_id', 'product_id', 'product_uom_qty') def onchange_product_id(self): """ On change of product it sets product quantity, tax account, name, uom of product, unit price and price subtotal. """ if not self.product_id: return partner = self.repair_id.partner_id pricelist = self.repair_id.pricelist_id if partner and self.product_id: self.tax_id = partner.property_account_position_id.map_tax(self.product_id.taxes_id, self.product_id, partner).ids if self.product_id: self.name = self.product_id.display_name self.product_uom = self.product_id.uom_id.id warning = False if not pricelist: warning = { 'title': _('No Pricelist!'), 'message': _('You have to select a pricelist in the Repair form !\n Please set one before choosing a product.')} else: price = pricelist.get_product_price(self.product_id, self.product_uom_qty, partner) if price is False: warning = { 'title': _('No valid pricelist line found !'), 'message': _("Couldn't find a pricelist line matching this product and quantity.\nYou have to change either the product, the quantity or the pricelist.")} else: self.price_unit = price if warning: return {'warning': warning}
class Product(models.Model): _inherit = "product.product" website_price = fields.Float('Website price', compute='_website_price', digits=dp.get_precision('Product Price')) website_public_price = fields.Float( 'Website public price', compute='_website_price', digits=dp.get_precision('Product Price')) def _website_price(self): qty = self._context.get('quantity', 1.0) partner = self.env.user.partner_id current_website = self.env['website'].get_current_website() pricelist = current_website.get_current_pricelist() company_id = current_website.company_id context = dict(self._context, pricelist=pricelist.id, partner=partner) self2 = self.with_context( context) if self._context != context else self ret = self.env.user.has_group( 'sale.group_show_price_subtotal' ) and 'total_excluded' or 'total_included' for p, p2 in pycompat.izip(self, self2): taxes = partner.property_account_position_id.map_tax( p.taxes_id.filtered(lambda x: x.company_id == company_id)) p.website_price = taxes.compute_all(p2.price, pricelist.currency_id, quantity=qty, product=p2, partner=partner)[ret] p.website_public_price = taxes.compute_all(p2.lst_price, quantity=qty, product=p2, partner=partner)[ret] @api.multi def website_publish_button(self): self.ensure_one() return self.product_tmpl_id.website_publish_button()
class PurchaseOrderLine(models.Model): _inherit = "purchase.order.line" @api.depends('discount') def _compute_amount(self): for line in self: price_unit = False # This is always executed for allowing other modules to use this # with different conditions than discount != 0 price = line._get_discounted_price_unit() if price != line.price_unit: # Only change value if it's different price_unit = line.price_unit line.price_unit = price super(PurchaseOrderLine, line)._compute_amount() if price_unit: line.price_unit = price_unit discount = fields.Float( string='Discount (%)', digits=dp.get_precision('Discount'), ) _sql_constraints = [ ('discount_limit', 'CHECK (discount <= 100.0)', 'Discount must be lower than 100%.'), ] def _get_discounted_price_unit(self): """Inheritable method for getting the unit price after applying discount(s). :rtype: float :return: Unit price after discount(s). """ self.ensure_one() if self.discount: return self.price_unit * (1 - self.discount / 100) return self.price_unit @api.multi def _get_stock_move_price_unit(self): """Get correct price with discount replacing current price_unit value before calling super and restoring it later for assuring maximum inheritability. """ price_unit = False price = self._get_discounted_price_unit() if price != self.price_unit: # Only change value if it's different price_unit = self.price_unit self.price_unit = price price = super(PurchaseOrderLine, self)._get_stock_move_price_unit() if price_unit: self.price_unit = price_unit return price
class LunchProduct(models.Model): """ Products available to order. A product is linked to a specific vendor. """ _name = 'lunch.product' _description = 'lunch product' name = fields.Char('Product', required=True) category_id = fields.Many2one('lunch.product.category', 'Category', required=True) description = fields.Text('Description') price = fields.Float('Price', digits=dp.get_precision('Account')) supplier = fields.Many2one('res.partner', 'Vendor') active = fields.Boolean(default=True)