How to use repair method in autotest

Best Python code snippet using autotest_python

repair.py

Source:repair.py Github

copy

Full Screen

1# Part of Odoo. See LICENSE file for full copyright and licensing details.2from collections import defaultdict3from random import randint4from markupsafe import Markup5from odoo import api, fields, models, _6from odoo.exceptions import UserError, ValidationError7from odoo.tools import float_compare, is_html_empty8class StockMove(models.Model):9 _inherit = 'stock.move'10 repair_id = fields.Many2one('repair.order', check_company=True)11class Repair(models.Model):12 _name = 'repair.order'13 _description = 'Repair Order'14 _inherit = ['mail.thread', 'mail.activity.mixin']15 _order = 'priority desc, create_date desc'16 name = fields.Char(17 'Repair Reference',18 default='New',19 copy=False, required=True,20 readonly=True)21 description = fields.Char('Repair Description')22 product_id = fields.Many2one(23 'product.product', string='Product to Repair',24 domain="[('type', 'in', ['product', 'consu']), '|', ('company_id', '=', company_id), ('company_id', '=', False)]",25 readonly=True, required=True, states={'draft': [('readonly', False)]}, check_company=True)26 product_qty = fields.Float(27 'Product Quantity',28 default=1.0, digits='Product Unit of Measure',29 readonly=True, required=True, states={'draft': [('readonly', False)]})30 product_uom = fields.Many2one(31 'uom.uom', 'Product Unit of Measure',32 readonly=True, required=True, states={'draft': [('readonly', False)]}, domain="[('category_id', '=', product_uom_category_id)]")33 product_uom_category_id = fields.Many2one(related='product_id.uom_id.category_id')34 partner_id = fields.Many2one(35 'res.partner', 'Customer',36 index=True, states={'confirmed': [('readonly', True)]}, check_company=True, change_default=True,37 help='Choose partner for whom the order will be invoiced and delivered. You can find a partner by its Name, TIN, Email or Internal Reference.')38 address_id = fields.Many2one(39 'res.partner', 'Delivery Address',40 domain="[('parent_id','=',partner_id)]", check_company=True,41 states={'confirmed': [('readonly', True)]})42 default_address_id = fields.Many2one('res.partner', compute='_compute_default_address_id')43 state = fields.Selection([44 ('draft', 'Quotation'),45 ('confirmed', 'Confirmed'),46 ('ready', 'Ready to Repair'),47 ('under_repair', 'Under Repair'),48 ('2binvoiced', 'To be Invoiced'),49 ('done', 'Repaired'),50 ('cancel', 'Cancelled')], string='Status',51 copy=False, default='draft', readonly=True, tracking=True,52 help="* The \'Draft\' status is used when a user is encoding a new and unconfirmed repair order.\n"53 "* The \'Confirmed\' status is used when a user confirms the repair order.\n"54 "* The \'Ready to Repair\' status is used to start to repairing, user can start repairing only after repair order is confirmed.\n"55 "* The \'Under Repair\' status is used when the repair is ongoing.\n"56 "* The \'To be Invoiced\' status is used to generate the invoice before or after repairing done.\n"57 "* The \'Done\' status is set when repairing is completed.\n"58 "* The \'Cancelled\' status is used when user cancel repair order.")59 schedule_date = fields.Date("Scheduled Date")60 location_id = fields.Many2one(61 'stock.location', 'Location',62 index=True, readonly=True, required=True, check_company=True,63 help="This is the location where the product to repair is located.",64 states={'draft': [('readonly', False)], 'confirmed': [('readonly', True)]})65 lot_id = fields.Many2one(66 'stock.production.lot', 'Lot/Serial',67 domain="[('product_id','=', product_id), ('company_id', '=', company_id)]", check_company=True,68 help="Products repaired are all belonging to this lot")69 guarantee_limit = fields.Date('Warranty Expiration', states={'confirmed': [('readonly', True)]})70 operations = fields.One2many(71 'repair.line', 'repair_id', 'Parts',72 copy=True)73 pricelist_id = fields.Many2one(74 'product.pricelist', 'Pricelist',75 default=lambda self: self.env['product.pricelist'].search([('company_id', 'in', [self.env.company.id, False])], limit=1).id,76 help='Pricelist of the selected partner.', check_company=True)77 currency_id = fields.Many2one(related='pricelist_id.currency_id')78 partner_invoice_id = fields.Many2one('res.partner', 'Invoicing Address', check_company=True)79 invoice_method = fields.Selection([80 ("none", "No Invoice"),81 ("b4repair", "Before Repair"),82 ("after_repair", "After Repair")], string="Invoice Method",83 default='none', index=True, readonly=True, required=True,84 states={'draft': [('readonly', False)]},85 help='Selecting \'Before Repair\' or \'After Repair\' will allow you to generate invoice before or after the repair is done respectively. \'No invoice\' means you don\'t want to generate invoice for this repair order.')86 invoice_id = fields.Many2one(87 'account.move', 'Invoice',88 copy=False, readonly=True, tracking=True,89 domain=[('move_type', '=', 'out_invoice')])90 move_id = fields.Many2one(91 'stock.move', 'Move',92 copy=False, readonly=True, tracking=True, check_company=True,93 help="Move created by the repair order")94 fees_lines = fields.One2many(95 'repair.fee', 'repair_id', 'Operations',96 copy=True, readonly=False)97 internal_notes = fields.Html('Internal Notes')98 quotation_notes = fields.Html('Quotation Notes')99 user_id = fields.Many2one('res.users', string="Responsible", default=lambda self: self.env.user, check_company=True)100 company_id = fields.Many2one(101 'res.company', 'Company',102 readonly=True, required=True, index=True,103 default=lambda self: self.env.company)104 sale_order_id = fields.Many2one('sale.order', 'Sale Order', copy=False, help="Sale Order from which the product to be repaired comes from.")105 tag_ids = fields.Many2many('repair.tags', string="Tags")106 invoiced = fields.Boolean('Invoiced', copy=False, readonly=True)107 repaired = fields.Boolean('Repaired', copy=False, readonly=True)108 amount_untaxed = fields.Float('Untaxed Amount', compute='_amount_untaxed', store=True)109 amount_tax = fields.Float('Taxes', compute='_amount_tax', store=True)110 amount_total = fields.Float('Total', compute='_amount_total', store=True)111 tracking = fields.Selection(string='Product Tracking', related="product_id.tracking", readonly=False)112 invoice_state = fields.Selection(string='Invoice State', related='invoice_id.state')113 priority = fields.Selection([('0', 'Normal'), ('1', 'Urgent')], default='0', string="Priority", help="Important repair order")114 @api.depends('partner_id')115 def _compute_default_address_id(self):116 for order in self:117 if order.partner_id:118 order.default_address_id = order.partner_id.address_get(['contact'])['contact']119 @api.depends('operations.price_subtotal', 'invoice_method', 'fees_lines.price_subtotal', 'pricelist_id.currency_id')120 def _amount_untaxed(self):121 for order in self:122 total = sum(operation.price_subtotal for operation in order.operations)123 total += sum(fee.price_subtotal for fee in order.fees_lines)124 currency = order.pricelist_id.currency_id or self.env.company.currency_id125 order.amount_untaxed = currency.round(total)126 @api.depends('operations.price_unit', 'operations.product_uom_qty', 'operations.product_id',127 'fees_lines.price_unit', 'fees_lines.product_uom_qty', 'fees_lines.product_id',128 'pricelist_id.currency_id', 'partner_id')129 def _amount_tax(self):130 for order in self:131 val = 0.0132 currency = order.pricelist_id.currency_id or self.env.company.currency_id133 for operation in order.operations:134 if operation.tax_id:135 tax_calculate = operation.tax_id.compute_all(operation.price_unit, currency, operation.product_uom_qty, operation.product_id, order.partner_id)136 for c in tax_calculate['taxes']:137 val += c['amount']138 for fee in order.fees_lines:139 if fee.tax_id:140 tax_calculate = fee.tax_id.compute_all(fee.price_unit, currency, fee.product_uom_qty, fee.product_id, order.partner_id)141 for c in tax_calculate['taxes']:142 val += c['amount']143 order.amount_tax = val144 @api.depends('amount_untaxed', 'amount_tax')145 def _amount_total(self):146 for order in self:147 currency = order.pricelist_id.currency_id or self.env.company.currency_id148 order.amount_total = currency.round(order.amount_untaxed + order.amount_tax)149 _sql_constraints = [150 ('name', 'unique (name)', 'The name of the Repair Order must be unique!'),151 ]152 @api.onchange('product_id')153 def onchange_product_id(self):154 self.guarantee_limit = False155 if (self.product_id and self.lot_id and self.lot_id.product_id != self.product_id) or not self.product_id:156 self.lot_id = False157 if self.product_id:158 self.product_uom = self.product_id.uom_id.id159 @api.onchange('product_uom')160 def onchange_product_uom(self):161 res = {}162 if not self.product_id or not self.product_uom:163 return res164 if self.product_uom.category_id != self.product_id.uom_id.category_id:165 res['warning'] = {'title': _('Warning'), 'message': _('The product unit of measure you chose has a different category than the product unit of measure.')}166 self.product_uom = self.product_id.uom_id.id167 return res168 @api.onchange('partner_id')169 def onchange_partner_id(self):170 self = self.with_company(self.company_id)171 if not self.partner_id:172 self.address_id = False173 self.partner_invoice_id = False174 self.pricelist_id = self.env['product.pricelist'].search([175 ('company_id', 'in', [self.env.company.id, False]),176 ], limit=1)177 else:178 addresses = self.partner_id.address_get(['delivery', 'invoice', 'contact'])179 self.address_id = addresses['delivery'] or addresses['contact']180 self.partner_invoice_id = addresses['invoice']181 self.pricelist_id = self.partner_id.property_product_pricelist.id182 @api.onchange('company_id')183 def _onchange_company_id(self):184 if self.company_id:185 if self.location_id.company_id != self.company_id:186 warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.company_id.id)], limit=1)187 self.location_id = warehouse.lot_stock_id188 else:189 self.location_id = False190 @api.ondelete(at_uninstall=False)191 def _unlink_except_confirmed(self):192 for order in self:193 if order.invoice_id and order.invoice_id.posted_before:194 raise UserError(_('You can not delete a repair order which is linked to an invoice which has been posted once.'))195 if order.state not in ('draft', 'cancel'):196 raise UserError(_('You can not delete a repair order once it has been confirmed. You must first cancel it.'))197 @api.model198 def create(self, vals):199 # We generate a standard reference200 vals['name'] = self.env['ir.sequence'].next_by_code('repair.order') or '/'201 return super(Repair, self).create(vals)202 def button_dummy(self):203 # TDE FIXME: this button is very interesting204 return True205 def action_repair_cancel_draft(self):206 if self.filtered(lambda repair: repair.state != 'cancel'):207 raise UserError(_("Repair must be canceled in order to reset it to draft."))208 self.mapped('operations').write({'state': 'draft'})209 return self.write({'state': 'draft', 'invoice_id': False})210 def action_validate(self):211 self.ensure_one()212 if self.filtered(lambda repair: any(op.product_uom_qty < 0 for op in repair.operations)):213 raise UserError(_("You can not enter negative quantities."))214 if self.product_id.type == 'consu':215 return self.action_repair_confirm()216 precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')217 available_qty_owner = self.env['stock.quant']._get_available_quantity(self.product_id, self.location_id, self.lot_id, owner_id=self.partner_id, strict=True)218 available_qty_noown = self.env['stock.quant']._get_available_quantity(self.product_id, self.location_id, self.lot_id, strict=True)219 repair_qty = self.product_uom._compute_quantity(self.product_qty, self.product_id.uom_id)220 for available_qty in [available_qty_owner, available_qty_noown]:221 if float_compare(available_qty, repair_qty, precision_digits=precision) >= 0:222 return self.action_repair_confirm()223 else:224 return {225 'name': self.product_id.display_name + _(': Insufficient Quantity To Repair'),226 'view_mode': 'form',227 'res_model': 'stock.warn.insufficient.qty.repair',228 'view_id': self.env.ref('repair.stock_warn_insufficient_qty_repair_form_view').id,229 'type': 'ir.actions.act_window',230 'context': {231 'default_product_id': self.product_id.id,232 'default_location_id': self.location_id.id,233 'default_repair_id': self.id,234 'default_quantity': repair_qty,235 'default_product_uom_name': self.product_id.uom_name236 },237 'target': 'new'238 }239 def action_repair_confirm(self):240 """ Repair order state is set to 'To be invoiced' when invoice method241 is 'Before repair' else state becomes 'Confirmed'.242 @param *arg: Arguments243 @return: True244 """245 if self.filtered(lambda repair: repair.state != 'draft'):246 raise UserError(_("Only draft repairs can be confirmed."))247 self._check_company()248 self.operations._check_company()249 self.fees_lines._check_company()250 before_repair = self.filtered(lambda repair: repair.invoice_method == 'b4repair')251 before_repair.write({'state': '2binvoiced'})252 to_confirm = self - before_repair253 to_confirm_operations = to_confirm.mapped('operations')254 to_confirm_operations.write({'state': 'confirmed'})255 to_confirm.write({'state': 'confirmed'})256 return True257 def action_repair_cancel(self):258 invoice_to_cancel = self.filtered(lambda repair: repair.invoice_id.state == 'draft').invoice_id259 if invoice_to_cancel:260 invoice_to_cancel.button_cancel()261 self.mapped('operations').write({'state': 'cancel'})262 return self.write({'state': 'cancel'})263 def action_send_mail(self):264 self.ensure_one()265 template_id = self.env.ref('repair.mail_template_repair_quotation').id266 ctx = {267 'default_model': 'repair.order',268 'default_res_id': self.id,269 'default_use_template': bool(template_id),270 'default_template_id': template_id,271 'default_composition_mode': 'comment',272 'custom_layout': 'mail.mail_notification_light',273 }274 return {275 'type': 'ir.actions.act_window',276 'view_mode': 'form',277 'res_model': 'mail.compose.message',278 'target': 'new',279 'context': ctx,280 }281 def print_repair_order(self):282 return self.env.ref('repair.action_report_repair_order').report_action(self)283 def action_repair_invoice_create(self):284 for repair in self:285 repair._create_invoices()286 if repair.invoice_method == 'b4repair':287 repair.action_repair_ready()288 elif repair.invoice_method == 'after_repair':289 repair.write({'state': 'done'})290 return True291 def _create_invoices(self, group=False):292 """ Creates invoice(s) for repair order.293 @param group: It is set to true when group invoice is to be generated.294 @return: Invoice Ids.295 """296 grouped_invoices_vals = {}297 repairs = self.filtered(lambda repair: repair.state not in ('draft', 'cancel')298 and not repair.invoice_id299 and repair.invoice_method != 'none')300 for repair in repairs:301 repair = repair.with_company(repair.company_id)302 partner_invoice = repair.partner_invoice_id or repair.partner_id303 if not partner_invoice:304 raise UserError(_('You have to select an invoice address in the repair form.'))305 narration = repair.quotation_notes306 currency = repair.pricelist_id.currency_id307 company = repair.env.company308 journal = repair.env['account.move'].with_context(move_type='out_invoice')._get_default_journal()309 if not journal:310 raise UserError(_('Please define an accounting sales journal for the company %s (%s).') % (company.name, company.id))311 if (partner_invoice.id, currency.id, company.id) not in grouped_invoices_vals:312 grouped_invoices_vals[(partner_invoice.id, currency.id, company.id)] = []313 current_invoices_list = grouped_invoices_vals[(partner_invoice.id, currency.id, company.id)]314 if not group or len(current_invoices_list) == 0:315 fpos = self.env['account.fiscal.position'].get_fiscal_position(partner_invoice.id, delivery_id=repair.address_id.id)316 invoice_vals = {317 'move_type': 'out_invoice',318 'partner_id': partner_invoice.id,319 'partner_shipping_id': repair.address_id.id,320 'currency_id': currency.id,321 'narration': narration if not is_html_empty(narration) else '',322 'invoice_origin': repair.name,323 'repair_ids': [(4, repair.id)],324 'invoice_line_ids': [],325 'fiscal_position_id': fpos.id326 }327 if partner_invoice.property_payment_term_id:328 invoice_vals['invoice_payment_term_id'] = partner_invoice.property_payment_term_id.id329 current_invoices_list.append(invoice_vals)330 else:331 # if group == True: concatenate invoices by partner and currency332 invoice_vals = current_invoices_list[0]333 invoice_vals['invoice_origin'] += ', ' + repair.name334 invoice_vals['repair_ids'].append((4, repair.id))335 if not is_html_empty(narration):336 if is_html_empty(invoice_vals['narration']):337 invoice_vals['narration'] = narration338 else:339 invoice_vals['narration'] += Markup('<br/>') + narration340 # Create invoice lines from operations.341 for operation in repair.operations.filtered(lambda op: op.type == 'add'):342 if group:343 name = repair.name + '-' + operation.name344 else:345 name = operation.name346 account = operation.product_id.product_tmpl_id.get_product_accounts(fiscal_pos=fpos)['income']347 if not account:348 raise UserError(_('No account defined for product "%s".', operation.product_id.name))349 invoice_line_vals = {350 'name': name,351 'account_id': account.id,352 'quantity': operation.product_uom_qty,353 'tax_ids': [(6, 0, operation.tax_id.ids)],354 'product_uom_id': operation.product_uom.id,355 'price_unit': operation.price_unit,356 'product_id': operation.product_id.id,357 'repair_line_ids': [(4, operation.id)],358 }359 if currency == company.currency_id:360 balance = -(operation.product_uom_qty * operation.price_unit)361 invoice_line_vals.update({362 'debit': balance > 0.0 and balance or 0.0,363 'credit': balance < 0.0 and -balance or 0.0,364 })365 else:366 amount_currency = -(operation.product_uom_qty * operation.price_unit)367 balance = currency._convert(amount_currency, company.currency_id, company, fields.Date.today())368 invoice_line_vals.update({369 'amount_currency': amount_currency,370 'debit': balance > 0.0 and balance or 0.0,371 'credit': balance < 0.0 and -balance or 0.0,372 'currency_id': currency.id,373 })374 invoice_vals['invoice_line_ids'].append((0, 0, invoice_line_vals))375 # Create invoice lines from fees.376 for fee in repair.fees_lines:377 if group:378 name = repair.name + '-' + fee.name379 else:380 name = fee.name381 if not fee.product_id:382 raise UserError(_('No product defined on fees.'))383 account = fee.product_id.product_tmpl_id.get_product_accounts(fiscal_pos=fpos)['income']384 if not account:385 raise UserError(_('No account defined for product "%s".', fee.product_id.name))386 invoice_line_vals = {387 'name': name,388 'account_id': account.id,389 'quantity': fee.product_uom_qty,390 'tax_ids': [(6, 0, fee.tax_id.ids)],391 'product_uom_id': fee.product_uom.id,392 'price_unit': fee.price_unit,393 'product_id': fee.product_id.id,394 'repair_fee_ids': [(4, fee.id)],395 }396 if currency == company.currency_id:397 balance = -(fee.product_uom_qty * fee.price_unit)398 invoice_line_vals.update({399 'debit': balance > 0.0 and balance or 0.0,400 'credit': balance < 0.0 and -balance or 0.0,401 })402 else:403 amount_currency = -(fee.product_uom_qty * fee.price_unit)404 balance = currency._convert(amount_currency, company.currency_id, company,405 fields.Date.today())406 invoice_line_vals.update({407 'amount_currency': amount_currency,408 'debit': balance > 0.0 and balance or 0.0,409 'credit': balance < 0.0 and -balance or 0.0,410 'currency_id': currency.id,411 })412 invoice_vals['invoice_line_ids'].append((0, 0, invoice_line_vals))413 # Create invoices.414 invoices_vals_list_per_company = defaultdict(list)415 for (partner_invoice_id, currency_id, company_id), invoices in grouped_invoices_vals.items():416 for invoice in invoices:417 invoices_vals_list_per_company[company_id].append(invoice)418 for company_id, invoices_vals_list in invoices_vals_list_per_company.items():419 # VFE TODO remove the default_company_id ctxt key ?420 # Account fallbacks on self.env.company, which is correct with with_company421 self.env['account.move'].with_company(company_id).with_context(default_company_id=company_id, default_move_type='out_invoice').create(invoices_vals_list)422 repairs.write({'invoiced': True})423 repairs.mapped('operations').filtered(lambda op: op.type == 'add').write({'invoiced': True})424 repairs.mapped('fees_lines').write({'invoiced': True})425 return dict((repair.id, repair.invoice_id.id) for repair in repairs)426 def action_created_invoice(self):427 self.ensure_one()428 return {429 'name': _('Invoice created'),430 'type': 'ir.actions.act_window',431 'view_mode': 'form',432 'res_model': 'account.move',433 'view_id': self.env.ref('account.view_move_form').id,434 'target': 'current',435 'res_id': self.invoice_id.id,436 }437 def action_repair_ready(self):438 self.mapped('operations').write({'state': 'confirmed'})439 return self.write({'state': 'ready'})440 def action_repair_start(self):441 """ Writes repair order state to 'Under Repair'442 @return: True443 """444 if self.filtered(lambda repair: repair.state not in ['confirmed', 'ready']):445 raise UserError(_("Repair must be confirmed before starting reparation."))446 self.mapped('operations').write({'state': 'confirmed'})447 return self.write({'state': 'under_repair'})448 def action_repair_end(self):449 """ Writes repair order state to 'To be invoiced' if invoice method is450 After repair else state is set to 'Ready'.451 @return: True452 """453 if self.filtered(lambda repair: repair.state != 'under_repair'):454 raise UserError(_("Repair must be under repair in order to end reparation."))455 self._check_product_tracking()456 for repair in self:457 repair.write({'repaired': True})458 vals = {'state': 'done'}459 vals['move_id'] = repair.action_repair_done().get(repair.id)460 if not repair.invoice_id and repair.invoice_method == 'after_repair':461 vals['state'] = '2binvoiced'462 repair.write(vals)463 return True464 def action_repair_done(self):465 """ Creates stock move for operation and stock move for final product of repair order.466 @return: Move ids of final products467 """468 if self.filtered(lambda repair: not repair.repaired):469 raise UserError(_("Repair must be repaired in order to make the product moves."))470 self._check_company()471 self.operations._check_company()472 self.fees_lines._check_company()473 res = {}474 precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')475 Move = self.env['stock.move']476 for repair in self:477 # Try to create move with the appropriate owner478 owner_id = False479 available_qty_owner = self.env['stock.quant']._get_available_quantity(repair.product_id, repair.location_id, repair.lot_id, owner_id=repair.partner_id, strict=True)480 if float_compare(available_qty_owner, repair.product_qty, precision_digits=precision) >= 0:481 owner_id = repair.partner_id.id482 moves = self.env['stock.move']483 for operation in repair.operations:484 move = Move.create({485 'name': repair.name,486 'product_id': operation.product_id.id,487 'product_uom_qty': operation.product_uom_qty,488 'product_uom': operation.product_uom.id,489 'partner_id': repair.address_id.id,490 'location_id': operation.location_id.id,491 'location_dest_id': operation.location_dest_id.id,492 'repair_id': repair.id,493 'origin': repair.name,494 'company_id': repair.company_id.id,495 })496 # Best effort to reserve the product in a (sub)-location where it is available497 product_qty = move.product_uom._compute_quantity(498 operation.product_uom_qty, move.product_id.uom_id, rounding_method='HALF-UP')499 available_quantity = self.env['stock.quant']._get_available_quantity(500 move.product_id,501 move.location_id,502 lot_id=operation.lot_id,503 strict=False,504 )505 move._update_reserved_quantity(506 product_qty,507 available_quantity,508 move.location_id,509 lot_id=operation.lot_id,510 strict=False,511 )512 # Then, set the quantity done. If the required quantity was not reserved, negative513 # quant is created in operation.location_id.514 move._set_quantity_done(operation.product_uom_qty)515 if operation.lot_id:516 move.move_line_ids.lot_id = operation.lot_id517 moves |= move518 operation.write({'move_id': move.id, 'state': 'done'})519 move = Move.create({520 'name': repair.name,521 'product_id': repair.product_id.id,522 'product_uom': repair.product_uom.id or repair.product_id.uom_id.id,523 'product_uom_qty': repair.product_qty,524 'partner_id': repair.address_id.id,525 'location_id': repair.location_id.id,526 'location_dest_id': repair.location_id.id,527 'move_line_ids': [(0, 0, {'product_id': repair.product_id.id,528 'lot_id': repair.lot_id.id,529 'product_uom_qty': 0, # bypass reservation here530 'product_uom_id': repair.product_uom.id or repair.product_id.uom_id.id,531 'qty_done': repair.product_qty,532 'package_id': False,533 'result_package_id': False,534 'owner_id': owner_id,535 'location_id': repair.location_id.id, #TODO: owner stuff536 'company_id': repair.company_id.id,537 'location_dest_id': repair.location_id.id,})],538 'repair_id': repair.id,539 'origin': repair.name,540 'company_id': repair.company_id.id,541 })542 consumed_lines = moves.mapped('move_line_ids')543 produced_lines = move.move_line_ids544 moves |= move545 moves._action_done()546 produced_lines.write({'consume_line_ids': [(6, 0, consumed_lines.ids)]})547 res[repair.id] = move.id548 return res549 def _check_product_tracking(self):550 invalid_lines = self.operations.filtered(lambda x: x.tracking != 'none' and not x.lot_id)551 if invalid_lines:552 products = invalid_lines.product_id553 raise ValidationError(_(554 "Serial number is required for operation lines with products: %s",555 ", ".join(products.mapped('display_name')),556 ))557class RepairLine(models.Model):558 _name = 'repair.line'559 _description = 'Repair Line (parts)'560 name = fields.Text('Description', required=True)561 repair_id = fields.Many2one(562 'repair.order', 'Repair Order Reference', required=True,563 index=True, ondelete='cascade', check_company=True)564 company_id = fields.Many2one(565 related='repair_id.company_id', store=True, index=True)566 currency_id = fields.Many2one(567 related='repair_id.currency_id')568 type = fields.Selection([569 ('add', 'Add'),570 ('remove', 'Remove')], 'Type', default='add', required=True)571 product_id = fields.Many2one(572 'product.product', 'Product', required=True, check_company=True,573 domain="[('type', 'in', ['product', 'consu']), '|', ('company_id', '=', company_id), ('company_id', '=', False)]")574 invoiced = fields.Boolean('Invoiced', copy=False, readonly=True)575 price_unit = fields.Float('Unit Price', required=True, digits='Product Price')576 price_subtotal = fields.Float('Subtotal', compute='_compute_price_subtotal', store=True, digits=0)577 price_total = fields.Float('Total', compute='_compute_price_total', compute_sudo=True, digits=0)578 tax_id = fields.Many2many(579 'account.tax', 'repair_operation_line_tax', 'repair_operation_line_id', 'tax_id', 'Taxes',580 domain="[('type_tax_use','=','sale'), ('company_id', '=', company_id)]", check_company=True)581 product_uom_qty = fields.Float(582 'Quantity', default=1.0,583 digits='Product Unit of Measure', required=True)584 product_uom = fields.Many2one(585 'uom.uom', 'Product Unit of Measure',586 required=True, domain="[('category_id', '=', product_uom_category_id)]")587 product_uom_category_id = fields.Many2one(related='product_id.uom_id.category_id')588 invoice_line_id = fields.Many2one(589 'account.move.line', 'Invoice Line',590 copy=False, readonly=True, check_company=True)591 location_id = fields.Many2one(592 'stock.location', 'Source Location',593 index=True, required=True, check_company=True)594 location_dest_id = fields.Many2one(595 'stock.location', 'Dest. Location',596 index=True, required=True, check_company=True)597 move_id = fields.Many2one(598 'stock.move', 'Inventory Move',599 copy=False, readonly=True)600 lot_id = fields.Many2one(601 'stock.production.lot', 'Lot/Serial',602 domain="[('product_id','=', product_id), ('company_id', '=', company_id)]", check_company=True)603 state = fields.Selection([604 ('draft', 'Draft'),605 ('confirmed', 'Confirmed'),606 ('done', 'Done'),607 ('cancel', 'Cancelled')], 'Status', default='draft',608 copy=False, readonly=True, required=True,609 help='The status of a repair line is set automatically to the one of the linked repair order.')610 tracking = fields.Selection(string='Product Tracking', related="product_id.tracking")611 @api.depends('price_unit', 'repair_id', 'product_uom_qty', 'product_id', 'repair_id.invoice_method')612 def _compute_price_subtotal(self):613 for line in self:614 taxes = line.tax_id.compute_all(line.price_unit, line.repair_id.pricelist_id.currency_id, line.product_uom_qty, line.product_id, line.repair_id.partner_id)615 line.price_subtotal = taxes['total_excluded']616 @api.depends('price_unit', 'repair_id', 'product_uom_qty', 'product_id', 'tax_id', 'repair_id.invoice_method')617 def _compute_price_total(self):618 for line in self:619 taxes = line.tax_id.compute_all(line.price_unit, line.repair_id.pricelist_id.currency_id, line.product_uom_qty, line.product_id, line.repair_id.partner_id)620 line.price_total = taxes['total_included']621 @api.onchange('type')622 def onchange_operation_type(self):623 """ On change of operation type it sets source location, destination location624 and to invoice field.625 @param product: Changed operation type.626 @param guarantee_limit: Guarantee limit of current record.627 @return: Dictionary of values.628 """629 if not self.type:630 self.location_id = False631 self.location_dest_id = False632 elif self.type == 'add':633 self.onchange_product_id()634 args = self.repair_id.company_id and [('company_id', '=', self.repair_id.company_id.id)] or []635 warehouse = self.env['stock.warehouse'].search(args, limit=1)636 self.location_id = warehouse.lot_stock_id637 self.location_dest_id = self.env['stock.location'].search([('usage', '=', 'production'), ('company_id', '=', self.repair_id.company_id.id)], limit=1)638 else:639 self.price_unit = 0.0640 self.tax_id = False641 self.location_id = self.env['stock.location'].search([('usage', '=', 'production'), ('company_id', '=', self.repair_id.company_id.id)], limit=1).id642 self.location_dest_id = self.env['stock.location'].search([('scrap_location', '=', True), ('company_id', 'in', [self.repair_id.company_id.id, False])], limit=1).id643 @api.onchange('repair_id', 'product_id', 'product_uom_qty')644 def onchange_product_id(self):645 """ On change of product it sets product quantity, tax account, name,646 uom of product, unit price and price subtotal. """647 if not self.product_id or not self.product_uom_qty:648 return649 self = self.with_company(self.company_id)650 partner = self.repair_id.partner_id651 partner_invoice = self.repair_id.partner_invoice_id or partner652 if partner:653 self = self.with_context(lang=partner.lang)654 product = self.product_id655 self.name = product.display_name656 if product.description_sale:657 if partner:658 self.name += '\n' + self.product_id.with_context(lang=partner.lang).description_sale659 else:660 self.name += '\n' + self.product_id.description_sale661 self.product_uom = product.uom_id.id662 if self.type != 'remove':663 if partner:664 fpos = self.env['account.fiscal.position'].get_fiscal_position(partner_invoice.id, delivery_id=self.repair_id.address_id.id)665 taxes = self.product_id.taxes_id.filtered(lambda x: x.company_id == self.repair_id.company_id)666 self.tax_id = fpos.map_tax(taxes)667 warning = False668 pricelist = self.repair_id.pricelist_id669 if not pricelist:670 warning = {671 'title': _('No pricelist found.'),672 'message':673 _('You have to select a pricelist in the Repair form !\n Please set one before choosing a product.')}674 return {'warning': warning}675 else:676 self._onchange_product_uom()677 @api.onchange('product_uom')678 def _onchange_product_uom(self):679 partner = self.repair_id.partner_id680 pricelist = self.repair_id.pricelist_id681 if pricelist and self.product_id and self.type != 'remove':682 price = pricelist.get_product_price(self.product_id, self.product_uom_qty, partner, uom_id=self.product_uom.id)683 if price is False:684 warning = {685 'title': _('No valid pricelist line found.'),686 'message':687 _("Couldn't find a pricelist line matching this product and quantity.\nYou have to change either the product, the quantity or the pricelist.")}688 return {'warning': warning}689 else:690 self.price_unit = price691class RepairFee(models.Model):692 _name = 'repair.fee'693 _description = 'Repair Fees'694 repair_id = fields.Many2one(695 'repair.order', 'Repair Order Reference',696 index=True, ondelete='cascade', required=True)697 company_id = fields.Many2one(698 related="repair_id.company_id", index=True, store=True)699 currency_id = fields.Many2one(700 related="repair_id.currency_id")701 name = fields.Text('Description', index=True, required=True)702 product_id = fields.Many2one(703 'product.product', 'Product', check_company=True,704 domain="[('type', '=', 'service'), '|', ('company_id', '=', company_id), ('company_id', '=', False)]")705 product_uom_qty = fields.Float('Quantity', digits='Product Unit of Measure', required=True, default=1.0)706 price_unit = fields.Float('Unit Price', required=True, digits='Product Price')707 product_uom = fields.Many2one('uom.uom', 'Product Unit of Measure', required=True, domain="[('category_id', '=', product_uom_category_id)]")708 product_uom_category_id = fields.Many2one(related='product_id.uom_id.category_id')709 price_subtotal = fields.Float('Subtotal', compute='_compute_price_subtotal', store=True, digits=0)710 price_total = fields.Float('Total', compute='_compute_price_total', compute_sudo=True, digits=0)711 tax_id = fields.Many2many(712 'account.tax', 'repair_fee_line_tax', 'repair_fee_line_id', 'tax_id', 'Taxes',713 domain="[('type_tax_use','=','sale'), ('company_id', '=', company_id)]", check_company=True)714 invoice_line_id = fields.Many2one('account.move.line', 'Invoice Line', copy=False, readonly=True, check_company=True)715 invoiced = fields.Boolean('Invoiced', copy=False, readonly=True)716 @api.depends('price_unit', 'repair_id', 'product_uom_qty', 'product_id')717 def _compute_price_subtotal(self):718 for fee in self:719 taxes = fee.tax_id.compute_all(fee.price_unit, fee.repair_id.pricelist_id.currency_id, fee.product_uom_qty, fee.product_id, fee.repair_id.partner_id)720 fee.price_subtotal = taxes['total_excluded']721 @api.depends('price_unit', 'repair_id', 'product_uom_qty', 'product_id', 'tax_id')722 def _compute_price_total(self):723 for fee in self:724 taxes = fee.tax_id.compute_all(fee.price_unit, fee.repair_id.pricelist_id.currency_id, fee.product_uom_qty, fee.product_id, fee.repair_id.partner_id)725 fee.price_total = taxes['total_included']726 @api.onchange('repair_id', 'product_id', 'product_uom_qty')727 def onchange_product_id(self):728 """ On change of product it sets product quantity, tax account, name,729 uom of product, unit price and price subtotal. """730 if not self.product_id:731 return732 self = self.with_company(self.company_id)733 partner = self.repair_id.partner_id734 partner_invoice = self.repair_id.partner_invoice_id or partner735 pricelist = self.repair_id.pricelist_id736 if partner and self.product_id:737 fpos = self.env['account.fiscal.position'].get_fiscal_position(partner_invoice.id, delivery_id=self.repair_id.address_id.id)738 taxes = self.product_id.taxes_id.filtered(lambda x: x.company_id == self.repair_id.company_id)739 self.tax_id = fpos.map_tax(taxes)740 if partner:741 self.name = self.product_id.with_context(lang=partner.lang).display_name742 else:743 self.name = self.product_id.display_name744 self.product_uom = self.product_id.uom_id.id745 if self.product_id.description_sale:746 if partner:747 self.name += '\n' + self.product_id.with_context(lang=partner.lang).description_sale748 else:749 self.name += '\n' + self.product_id.description_sale750 warning = False751 if not pricelist:752 warning = {753 'title': _('No pricelist found.'),754 'message':755 _('You have to select a pricelist in the Repair form !\n Please set one before choosing a product.')}756 return {'warning': warning}757 else:758 self._onchange_product_uom()759 @api.onchange('product_uom')760 def _onchange_product_uom(self):761 partner = self.repair_id.partner_id762 pricelist = self.repair_id.pricelist_id763 if pricelist and self.product_id:764 price = pricelist.get_product_price(self.product_id, self.product_uom_qty, partner, uom_id=self.product_uom.id)765 if price is False:766 warning = {767 'title': _('No valid pricelist line found.'),768 'message':769 _("Couldn't find a pricelist line matching this product and quantity.\nYou have to change either the product, the quantity or the pricelist.")}770 return {'warning': warning}771 else:772 self.price_unit = price773class RepairTags(models.Model):774 """ Tags of Repair's tasks """775 _name = "repair.tags"776 _description = "Repair Tags"777 def _get_default_color(self):778 return randint(1, 11)779 name = fields.Char('Tag Name', required=True)780 color = fields.Integer(string='Color Index', default=_get_default_color)781 _sql_constraints = [782 ('name_uniq', 'unique (name)', "Tag name already exists!"),...

Full Screen

Full Screen

test_repair.py

Source:test_repair.py Github

copy

Full Screen

1# -*- coding: utf-8 -*-2# Part of Odoo. See LICENSE file for full copyright and licensing details.3from odoo.addons.account.tests.common import AccountTestInvoicingCommon4from odoo.tests import tagged, Form5@tagged('post_install', '-at_install')6class TestRepair(AccountTestInvoicingCommon):7 @classmethod8 def setUpClass(cls, chart_template_ref=None):9 super().setUpClass(chart_template_ref=chart_template_ref)10 # Partners11 cls.res_partner_1 = cls.env['res.partner'].create({'name': 'Wood Corner'})12 cls.res_partner_address_1 = cls.env['res.partner'].create({'name': 'Willie Burke', 'parent_id': cls.res_partner_1.id})13 cls.res_partner_12 = cls.env['res.partner'].create({'name': 'Partner 12'})14 # Products15 cls.product_product_3 = cls.env['product.product'].create({'name': 'Desk Combination'})16 cls.product_product_11 = cls.env['product.product'].create({'name': 'Conference Chair'})17 cls.product_product_5 = cls.env['product.product'].create({'name': 'Product 5'})18 cls.product_product_6 = cls.env['product.product'].create({'name': 'Large Cabinet'})19 cls.product_product_12 = cls.env['product.product'].create({'name': 'Office Chair Black'})20 cls.product_product_13 = cls.env['product.product'].create({'name': 'Corner Desk Left Sit'})21 cls.product_product_2 = cls.env['product.product'].create({'name': 'Virtual Home Staging'})22 cls.product_service_order_repair = cls.env['product.product'].create({23 'name': 'Repair Services',24 'type': 'service',25 })26 # Location27 cls.stock_warehouse = cls.env['stock.warehouse'].search([('company_id', '=', cls.env.company.id)], limit=1)28 cls.stock_location_14 = cls.env['stock.location'].create({29 'name': 'Shelf 2',30 'location_id': cls.stock_warehouse.lot_stock_id.id,31 })32 # Repair Orders33 cls.repair1 = cls.env['repair.order'].create({34 'address_id': cls.res_partner_address_1.id,35 'guarantee_limit': '2019-01-01',36 'invoice_method': 'none',37 'user_id': False,38 'product_id': cls.product_product_3.id,39 'product_uom': cls.env.ref('uom.product_uom_unit').id,40 'partner_invoice_id': cls.res_partner_address_1.id,41 'location_id': cls.stock_warehouse.lot_stock_id.id,42 'operations': [43 (0, 0, {44 'location_dest_id': cls.product_product_11.property_stock_production.id,45 'location_id': cls.stock_warehouse.lot_stock_id.id,46 'name': cls.product_product_11.get_product_multiline_description_sale(),47 'product_id': cls.product_product_11.id,48 'product_uom': cls.env.ref('uom.product_uom_unit').id,49 'product_uom_qty': 1.0,50 'price_unit': 50.0,51 'state': 'draft',52 'type': 'add',53 'company_id': cls.env.company.id,54 })55 ],56 'fees_lines': [57 (0, 0, {58 'name': cls.product_service_order_repair.get_product_multiline_description_sale(),59 'product_id': cls.product_service_order_repair.id,60 'product_uom_qty': 1.0,61 'product_uom': cls.env.ref('uom.product_uom_unit').id,62 'price_unit': 50.0,63 'company_id': cls.env.company.id,64 })65 ],66 'partner_id': cls.res_partner_12.id,67 })68 cls.repair0 = cls.env['repair.order'].create({69 'product_id': cls.product_product_5.id,70 'product_uom': cls.env.ref('uom.product_uom_unit').id,71 'address_id': cls.res_partner_address_1.id,72 'guarantee_limit': '2019-01-01',73 'invoice_method': 'after_repair',74 'user_id': False,75 'partner_invoice_id': cls.res_partner_address_1.id,76 'location_id': cls.stock_warehouse.lot_stock_id.id,77 'operations': [78 (0, 0, {79 'location_dest_id': cls.product_product_12.property_stock_production.id,80 'location_id': cls.stock_warehouse.lot_stock_id.id,81 'name': cls.product_product_12.get_product_multiline_description_sale(),82 'price_unit': 50.0,83 'product_id': cls.product_product_12.id,84 'product_uom': cls.env.ref('uom.product_uom_unit').id,85 'product_uom_qty': 1.0,86 'state': 'draft',87 'type': 'add',88 'company_id': cls.env.company.id,89 })90 ],91 'fees_lines': [92 (0, 0, {93 'name': cls.product_service_order_repair.get_product_multiline_description_sale(),94 'product_id': cls.product_service_order_repair.id,95 'product_uom_qty': 1.0,96 'product_uom': cls.env.ref('uom.product_uom_unit').id,97 'price_unit': 50.0,98 'company_id': cls.env.company.id,99 })100 ],101 'partner_id': cls.res_partner_12.id,102 })103 cls.repair2 = cls.env['repair.order'].create({104 'product_id': cls.product_product_6.id,105 'product_uom': cls.env.ref('uom.product_uom_unit').id,106 'address_id': cls.res_partner_address_1.id,107 'guarantee_limit': '2019-01-01',108 'invoice_method': 'b4repair',109 'user_id': False,110 'partner_invoice_id': cls.res_partner_address_1.id,111 'location_id': cls.stock_location_14.id,112 'operations': [113 (0, 0, {114 'location_dest_id': cls.product_product_13.property_stock_production.id,115 'location_id': cls.stock_warehouse.lot_stock_id.id,116 'name': cls.product_product_13.get_product_multiline_description_sale(),117 'price_unit': 50.0,118 'product_id': cls.product_product_13.id,119 'product_uom': cls.env.ref('uom.product_uom_unit').id,120 'product_uom_qty': 1.0,121 'state': 'draft',122 'type': 'add',123 'company_id': cls.env.company.id,124 })125 ],126 'fees_lines': [127 (0, 0, {128 'name': cls.product_service_order_repair.get_product_multiline_description_sale(),129 'product_id': cls.product_service_order_repair.id,130 'product_uom_qty': 1.0,131 'product_uom': cls.env.ref('uom.product_uom_unit').id,132 'price_unit': 50.0,133 'company_id': cls.env.company.id,134 })135 ],136 'partner_id': cls.res_partner_12.id,137 })138 cls.env.user.groups_id |= cls.env.ref('stock.group_stock_user')139 def _create_simple_repair_order(self, invoice_method):140 product_to_repair = self.product_product_5141 partner = self.res_partner_address_1142 return self.env['repair.order'].create({143 'product_id': product_to_repair.id,144 'product_uom': product_to_repair.uom_id.id,145 'address_id': partner.id,146 'guarantee_limit': '2019-01-01',147 'invoice_method': invoice_method,148 'partner_invoice_id': partner.id,149 'location_id': self.stock_warehouse.lot_stock_id.id,150 'partner_id': self.res_partner_12.id151 })152 def _create_simple_operation(self, repair_id=False, qty=0.0, price_unit=0.0):153 product_to_add = self.product_product_5154 return self.env['repair.line'].create({155 'name': 'Add The product',156 'type': 'add',157 'product_id': product_to_add.id,158 'product_uom_qty': qty,159 'product_uom': product_to_add.uom_id.id,160 'price_unit': price_unit,161 'repair_id': repair_id,162 'location_id': self.stock_warehouse.lot_stock_id.id,163 'location_dest_id': product_to_add.property_stock_production.id,164 'company_id': self.env.company.id,165 })166 def _create_simple_fee(self, repair_id=False, qty=0.0, price_unit=0.0):167 product_service = self.product_product_2168 return self.env['repair.fee'].create({169 'name': 'PC Assemble + Custom (PC on Demand)',170 'product_id': product_service.id,171 'product_uom_qty': qty,172 'product_uom': product_service.uom_id.id,173 'price_unit': price_unit,174 'repair_id': repair_id,175 'company_id': self.env.company.id,176 })177 def test_00_repair_afterinv(self):178 repair = self._create_simple_repair_order('after_repair')179 self._create_simple_operation(repair_id=repair.id, qty=1.0, price_unit=50.0)180 # I confirm Repair order taking Invoice Method 'After Repair'.181 repair.action_repair_confirm()182 # I check the state is in "Confirmed".183 self.assertEqual(repair.state, "confirmed", 'Repair order should be in "Confirmed" state.')184 repair.action_repair_start()185 # I check the state is in "Under Repair".186 self.assertEqual(repair.state, "under_repair", 'Repair order should be in "Under_repair" state.')187 # Repairing process for product is in Done state and I end Repair process by clicking on "End Repair" button.188 repair.action_repair_end()189 # I define Invoice Method 'After Repair' option in this Repair order.so I create invoice by clicking on "Make Invoice" wizard.190 make_invoice = self.env['repair.order.make_invoice'].create({191 'group': True})192 # I click on "Create Invoice" button of this wizard to make invoice.193 context = {194 "active_model": 'repair_order',195 "active_ids": [repair.id],196 "active_id": repair.id197 }198 make_invoice.with_context(context).make_invoices()199 # I check that invoice is created for this Repair order.200 self.assertEqual(len(repair.invoice_id), 1, "No invoice exists for this repair order")201 self.assertEqual(len(repair.move_id.move_line_ids[0].consume_line_ids), 1, "Consume lines should be set")202 def test_01_repair_b4inv(self):203 repair = self._create_simple_repair_order('b4repair')204 # I confirm Repair order for Invoice Method 'Before Repair'.205 repair.action_repair_confirm()206 # I click on "Create Invoice" button of this wizard to make invoice.207 repair.action_repair_invoice_create()208 # I check that invoice is created for this Repair order.209 self.assertEqual(len(repair.invoice_id), 1, "No invoice exists for this repair order")210 def test_02_repair_noneinv(self):211 repair = self._create_simple_repair_order('none')212 # Add a new fee line213 self._create_simple_fee(repair_id=repair.id, qty=1.0, price_unit=12.0)214 self.assertEqual(repair.amount_total, 12, "Amount_total should be 12")215 # Add new operation line216 self._create_simple_operation(repair_id=repair.id, qty=1.0, price_unit=14.0)217 self.assertEqual(repair.amount_total, 26, "Amount_total should be 26")218 # I confirm Repair order for Invoice Method 'No Invoice'.219 repair.action_repair_confirm()220 # I start the repairing process by clicking on "Start Repair" button for Invoice Method 'No Invoice'.221 repair.action_repair_start()222 # I check its state which is in "Under Repair".223 self.assertEqual(repair.state, "under_repair", 'Repair order should be in "Under_repair" state.')224 # Repairing process for product is in Done state and I end this process by clicking on "End Repair" button.225 repair.action_repair_end()226 self.assertEqual(repair.move_id.location_id.id, self.stock_warehouse.lot_stock_id.id,227 'Repaired product was taken in the wrong location')228 self.assertEqual(repair.move_id.location_dest_id.id, self.stock_warehouse.lot_stock_id.id,229 'Repaired product went to the wrong location')230 self.assertEqual(repair.operations.move_id.location_id.id, self.stock_warehouse.lot_stock_id.id,231 'Consumed product was taken in the wrong location')232 self.assertEqual(repair.operations.move_id.location_dest_id.id, self.product_product_5.property_stock_production.id,233 'Consumed product went to the wrong location')234 # I define Invoice Method 'No Invoice' option in this repair order.235 # So, I check that Invoice has not been created for this repair order.236 self.assertNotEqual(len(repair.invoice_id), 1, "Invoice should not exist for this repair order")237 def test_repair_state(self):238 repair = self._create_simple_repair_order('b4repair')239 repair.action_repair_confirm()240 repair.action_repair_invoice_create()241 repair.invoice_id.unlink()242 # Repair order state should be changed to 2binvoiced so that new invoice can be created243 self.assertEqual(repair.state, '2binvoiced', 'Repair order should be in 2binvoiced state, if invoice is deleted.')244 repair.action_repair_invoice_create()245 repair.action_repair_cancel()246 # Repair order and linked invoice both should be cancelled.247 self.assertEqual(repair.state, 'cancel', 'Repair order should be in cancel state.')248 self.assertEqual(repair.invoice_id.state, 'cancel', 'Invoice should be in cancel state.')249 repair.action_repair_cancel_draft()250 # Linked invoice should be unlinked251 self.assertEqual(len(repair.invoice_id), 0, "No invoice should be exists for this repair order")252 def test_03_repair_multicompany(self):253 """ This test ensures that the correct taxes are selected when the user fills in the RO form """254 company01 = self.env.company255 company02 = self.env['res.company'].create({256 'name': 'SuperCompany',257 })258 tax01 = self.env["account.tax"].create({259 "name": "C01 Tax",260 "amount": "0.00",261 "company_id": company01.id262 })263 tax02 = self.env["account.tax"].create({264 "name": "C02 Tax",265 "amount": "0.00",266 "company_id": company02.id267 })268 super_product = self.env['product.template'].create({269 "name": "SuperProduct",270 "taxes_id": [(4, tax01.id), (4, tax02.id)],271 })272 super_variant = super_product.product_variant_id273 self.assertEqual(super_variant.taxes_id, tax01 | tax02)274 ro_form = Form(self.env['repair.order'])275 ro_form.product_id = super_variant276 ro_form.partner_id = company01.partner_id277 with ro_form.operations.new() as ro_line:278 ro_line.product_id = super_variant279 with ro_form.fees_lines.new() as fee_line:280 fee_line.product_id = super_variant281 repair_order = ro_form.save()282 # tax02 should not be present since it belongs to the second company.283 self.assertEqual(repair_order.operations.tax_id, tax01)...

Full Screen

Full Screen

test_mrp_repair.py

Source:test_mrp_repair.py Github

copy

Full Screen

1# -*- coding: utf-8 -*-2# Part of Odoo. See LICENSE file for full copyright and licensing details.3from odoo.addons.account.tests.account_test_classes import AccountingTestCase4class TestMrpRepair(AccountingTestCase):5 def setUp(self):6 super(TestMrpRepair, self).setUp()7 self.MrpRepair = self.env['mrp.repair']8 self.ResUsers = self.env['res.users']9 self.MrpRepairMakeInvoice = self.env['mrp.repair.make_invoice']10 self.res_group_user = self.env.ref('stock.group_stock_user')11 self.res_group_manager = self.env.ref('stock.group_stock_manager')12 self.mrp_repair_rmrp0 = self.env.ref('mrp_repair.mrp_repair_rmrp0')13 self.mrp_repair_rmrp1 = self.env.ref('mrp_repair.mrp_repair_rmrp1')14 self.mrp_repair_rmrp2 = self.env.ref('mrp_repair.mrp_repair_rmrp2')15 self.res_mrp_repair_user = self.ResUsers.create({16 'name': 'MRP User',17 'login': 'maru',18 'password': 'maru',19 'email': 'mrp_repair_user@yourcompany.com',20 'groups_id': [(6, 0, [self.res_group_user.id])]})21 self.res_mrp_repair_manager = self.ResUsers.create({22 'name': 'MRP Manager',23 'login': 'marm',24 'password': 'marm',25 'email': 'mrp_repair_manager@yourcompany.com',26 'groups_id': [(6, 0, [self.res_group_manager.id])]})27 def test_00_mrp_repair_afterinv(self):28 # I confirm Repair order taking Invoice Method 'After Repair'.29 self.mrp_repair_rmrp0.sudo(self.res_mrp_repair_user.id).action_repair_confirm()30 # I check the state is in "Confirmed".31 self.assertEqual(self.mrp_repair_rmrp0.state, "confirmed", 'Mrp repair order should be in "Confirmed" state.')32 self.mrp_repair_rmrp0.action_repair_start()33 # I check the state is in "Under Repair".34 self.assertEqual(self.mrp_repair_rmrp0.state, "under_repair", 'Mrp repair order should be in "Under_repair" state.')35 # Repairing process for product is in Done state and I end Repair process by clicking on "End Repair" button.36 self.mrp_repair_rmrp0.action_repair_end()37 # I define Invoice Method 'After Repair' option in this Repair order.so I create invoice by clicking on "Make Invoice" wizard.38 mrp_make_invoice = self.MrpRepairMakeInvoice.create({39 'group': True})40 # I click on "Create Invoice" button of this wizard to make invoice.41 context = {42 "active_model": 'mrp_repair',43 "active_ids": [self.mrp_repair_rmrp0.id],44 "active_id": self.mrp_repair_rmrp0.id45 }46 mrp_make_invoice.with_context(context).make_invoices()47 # I check that invoice is created for this Repair order.48 self.assertEqual(len(self.mrp_repair_rmrp0.invoice_id), 1, "No invoice exists for this repair order")49 def test_01_mrp_repair_b4inv(self):50 # I confirm Repair order for Invoice Method 'Before Repair'.51 self.mrp_repair_rmrp2.sudo(self.res_mrp_repair_user.id).action_repair_confirm()52 # I click on "Create Invoice" button of this wizard to make invoice.53 self.mrp_repair_rmrp2.action_repair_invoice_create()54 # I check that invoice is created for this Repair order.55 self.assertEqual(len(self.mrp_repair_rmrp2.invoice_id), 1, "No invoice exists for this repair order")56 # I start the Repairing process by clicking on "Start Repair" button.57 self.mrp_repair_rmrp2.action_repair_start()58 # Repairing process for this product is in Done state and I end this process by clicking on "End Repair" button for Invoice Method 'Before Repair'.59 self.mrp_repair_rmrp2.action_repair_end()60 def test_02_mrp_repair_noneinv(self):61 # I confirm Repair order for Invoice Method 'No Invoice'.62 self.mrp_repair_rmrp1.sudo(self.res_mrp_repair_user.id).action_repair_confirm()63 # I start the repairing process by clicking on "Start Repair" button for Invoice Method 'No Invoice'.64 self.mrp_repair_rmrp1.action_repair_start()65 # I check its state which is in "Under Repair".66 self.assertEqual(self.mrp_repair_rmrp1.state, "under_repair", 'Mrp repair order should be in "Under_repair" state.')67 # Repairing process for product is in Done state and I end this process by clicking on "End Repair" button.68 self.mrp_repair_rmrp1.action_repair_end()69 # I define Invoice Method 'No Invoice' option in this repair order.70 # So, I check that Invoice has not been created for this repair order.71 self.assertNotEqual(len(self.mrp_repair_rmrp1.invoice_id), 1, "Invoice should not exist for this repair order")72 def test_03_mrp_repair_fee(self):73 # I check the total amount of mrp_repair_rmrp1 is 10074 self.assertEqual(self.mrp_repair_rmrp1.amount_total, 100, "Amount_total should be 100")75 # I add a new fee line76 product_assembly = self.env.ref('product.product_product_5')77 product_uom_hour = self.env.ref('product.product_uom_hour')78 self.MrpRepairFee = self.env['mrp.repair.fee']79 self.MrpRepairFee.create({80 'name': 'PC Assemble + Custom (PC on Demand)',81 'product_id': product_assembly.id,82 'product_uom_qty': 1.0,83 'product_uom': product_uom_hour.id,84 'price_unit': 12.0,85 'to_invoice': True,86 'repair_id': self.mrp_repair_rmrp1.id})87 # I check the total amount of mrp_repair_rmrp1 is now 112...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run autotest automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful