# -*- coding: utf-8 -*- ############################################################################## # # Cybrosys Technologies Pvt. Ltd. # Copyright (C) 2017-TODAY Cybrosys Technologies(). # Author: Saritha Sahadevan() # you can modify it under the terms of the GNU LESSER # GENERAL PUBLIC LICENSE (LGPL v3), Version 3. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. # # You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE # GENERAL PUBLIC LICENSE (LGPL v3) along with this program. # If not, see . # ############################################################################## from odoo.exceptions import UserError from odoo.tools.safe_eval import safe_eval from odoo import models, fields, api, _ class InvoiceStockMove(models.Model): _inherit = 'account.invoice' @api.model def _default_picking_receive(self): type_obj = self.env['stock.picking.type'] company_id = self.env.context.get('company_id') or self.env.user.company_id.id types = type_obj.search([('code', '=', 'incoming'), ('warehouse_id.company_id', '=', company_id)], limit=1) if not types: types = type_obj.search([('code', '=', 'incoming'), ('warehouse_id', '=', False)]) return types[:1] @api.model def _default_picking_transfer(self): type_obj = self.env['stock.picking.type'] company_id = self.env.context.get('company_id') or self.env.user.company_id.id types = type_obj.search([('code', '=', 'outgoing'), ('warehouse_id.company_id', '=', company_id)], limit=1) if not types: types = type_obj.search([('code', '=', 'outgoing'), ('warehouse_id', '=', False)]) return types[:4] picking_count = fields.Integer(string="Count") invoice_picking_id = fields.Many2one('stock.picking', string="Picking Id") picking_type_id = fields.Many2one('stock.picking.type', 'Picking Type', required=True, default=_default_picking_receive, help="This will determine picking type of incoming shipment") picking_transfer_id = fields.Many2one('stock.picking.type', 'Deliver To', required=True, default=_default_picking_transfer, help="This will determine picking type of outgoing shipment") state = fields.Selection([ ('draft', 'Draft'), ('proforma', 'Pro-forma'), ('proforma2', 'Pro-forma'), ('open', 'Open'), ('paid', 'Paid'), ('cancel', 'Cancelled'), ('done', 'Received'), ], string='Status', index=True, readonly=True, default='draft', track_visibility='onchange', copy=False) @api.multi def action_stock_receive(self): for order in self: if not order.invoice_line_ids: raise UserError(_('Please create some invoice lines.')) if not self.number: raise UserError(_('Please Validate invoice.')) if not self.invoice_picking_id: pick = { 'picking_type_id': self.picking_type_id.id, 'partner_id': self.partner_id.id, 'origin': self.number, 'location_dest_id': self.picking_type_id.default_location_dest_id.id, 'location_id': self.partner_id.property_stock_supplier.id } picking = self.env['stock.picking'].create(pick) self.invoice_picking_id = picking.id self.picking_count = len(picking) moves = order.invoice_line_ids.filtered( lambda r: r.product_id.type in ['product', 'consu'])._create_stock_moves(picking) move_ids = moves._action_confirm() move_ids._action_assign() @api.multi def action_stock_transfer(self): for order in self: if not order.invoice_line_ids: raise UserError(_('Please create some invoice lines.')) if not self.number: raise UserError(_('Please Validate invoice.')) if not self.invoice_picking_id: pick = { 'picking_type_id': self.picking_transfer_id.id, 'partner_id': self.partner_id.id, 'origin': self.number, 'location_dest_id': self.partner_id.property_stock_customer.id, 'location_id': self.picking_transfer_id.default_location_src_id.id } picking = self.env['stock.picking'].create(pick) self.invoice_picking_id = picking.id self.picking_count = len(picking) moves = order.invoice_line_ids.filtered( lambda r: r.product_id.type in ['product', 'consu'])._create_stock_moves_transfer(picking) move_ids = moves._action_confirm() move_ids._action_assign() @api.multi def action_view_picking(self): action = self.env.ref('stock.action_picking_tree_ready') result = action.read()[0] result.pop('id', None) result['context'] = {} result['domain'] = [('id', '=', self.invoice_picking_id.id)] pick_ids = sum([self.invoice_picking_id.id]) if pick_ids: res = self.env.ref('stock.view_picking_form', False) result['views'] = [(res and res.id or False, 'form')] result['res_id'] = pick_ids or False return result class SupplierInvoiceLine(models.Model): _inherit = 'account.invoice.line' @api.multi def _create_stock_moves(self, picking): moves = self.env['stock.move'] done = self.env['stock.move'].browse() for line in self: price_unit = line.price_unit template = { 'name': line.name or '', 'product_id': line.product_id.id, 'product_uom': line.uom_id.id, 'location_id': line.invoice_id.partner_id.property_stock_supplier.id, 'location_dest_id': picking.picking_type_id.default_location_dest_id.id, 'picking_id': picking.id, 'move_dest_id': False, 'state': 'draft', 'company_id': line.invoice_id.company_id.id, 'price_unit': price_unit, 'picking_type_id': picking.picking_type_id.id, 'procurement_id': False, 'route_ids': 1 and [ (6, 0, [x.id for x in self.env['stock.location.route'].search([('id', 'in', (2, 3))])])] or [], 'warehouse_id': picking.picking_type_id.warehouse_id.id, } diff_quantity = line.quantity tmp = template.copy() tmp.update({ 'product_uom_qty': diff_quantity, }) template['product_uom_qty'] = diff_quantity done += moves.create(template) return done def _create_stock_moves_transfer(self, picking): moves = self.env['stock.move'] done = self.env['stock.move'].browse() for line in self: price_unit = line.price_unit template = { 'name': line.name or '', 'product_id': line.product_id.id, 'product_uom': line.uom_id.id, 'location_id': picking.picking_type_id.default_location_src_id.id, 'location_dest_id': line.invoice_id.partner_id.property_stock_customer.id, 'picking_id': picking.id, 'move_dest_id': False, 'state': 'draft', 'company_id': line.invoice_id.company_id.id, 'price_unit': price_unit, 'picking_type_id': picking.picking_type_id.id, 'procurement_id': False, 'route_ids': 1 and [ (6, 0, [x.id for x in self.env['stock.location.route'].search([('id', 'in', (2, 3))])])] or [], 'warehouse_id': picking.picking_type_id.warehouse_id.id, } diff_quantity = line.quantity tmp = template.copy() tmp.update({ 'product_uom_qty': diff_quantity, }) template['product_uom_qty'] = diff_quantity done += moves.create(template) return done class AccountInvoiceRefund(models.TransientModel): _inherit = 'account.invoice.refund' @api.multi def compute_refund(self, mode='refund'): company_id = self.env.context.get('company_id') or self.env.user.company_id.id inv_obj = self.env['account.invoice'] inv_tax_obj = self.env['account.invoice.tax'] inv_line_obj = self.env['account.invoice.line'] context = dict(self._context or {}) xml_id = False for form in self: created_inv = [] date = False description = False for inv in inv_obj.browse(context.get('active_ids')): if inv.state in ['draft', 'cancel']: raise UserError(_('Cannot create credit note for the draft/cancelled invoice.')) if inv.reconciled and mode in ('cancel', 'modify'): raise UserError(_( 'Cannot create a credit note for the invoice which is already reconciled, invoice should be' ' unreconciled first, then only you can add credit note for this invoice.')) date = form.date or False description = form.description or inv.name refund = inv.refund(form.date_invoice, date, description, inv.journal_id.id) created_inv.append(refund.id) if inv.picking_transfer_id.code == 'outgoing': data = self.env['stock.picking.type'].search( [('warehouse_id.company_id', '=', company_id), ('code', '=', 'incoming')], limit=1) refund.picking_transfer_id = data.id if inv.picking_type_id.code == 'incoming': data = self.env['stock.picking.type'].search( [('warehouse_id.company_id', '=', company_id), ('code', '=', 'outgoing')], limit=1) refund.picking_type_id = data.id if mode in ('cancel', 'modify'): movelines = inv.move_id.line_ids to_reconcile_ids = {} to_reconcile_lines = self.env['account.move.line'] for line in movelines: if line.account_id.id == inv.account_id.id: to_reconcile_lines += line to_reconcile_ids.setdefault(line.account_id.id, []).append(line.id) if line.reconciled: line.remove_move_reconcile() refund.action_invoice_open() for tmpline in refund.move_id.line_ids: if tmpline.account_id.id == inv.account_id.id: to_reconcile_lines += tmpline to_reconcile_lines.filtered(lambda l: l.reconciled == False).reconcile() if mode == 'modify': invoice = inv.read(inv_obj._get_refund_modify_read_fields()) invoice = invoice[0] del invoice['id'] invoice_lines = inv_line_obj.browse(invoice['invoice_line_ids']) invoice_lines = inv_obj.with_context(mode='modify')._refund_cleanup_lines(invoice_lines) tax_lines = inv_tax_obj.browse(invoice['tax_line_ids']) tax_lines = inv_obj._refund_cleanup_lines(tax_lines) invoice.update({ 'type': inv.type, 'date_invoice': form.date_invoice, 'state': 'draft', 'number': False, 'invoice_line_ids': invoice_lines, 'tax_line_ids': tax_lines, 'date': date, 'origin': inv.origin, 'fiscal_position_id': inv.fiscal_position_id.id, }) for field in inv_obj._get_refund_common_fields(): if inv_obj._fields[field].type == 'many2one': invoice[field] = invoice[field] and invoice[field][0] else: invoice[field] = invoice[field] or False inv_refund = inv_obj.create(invoice) body = _( 'Correction of %s
Reason: %s') % ( inv.id, inv.number, description) inv_refund.message_post(body=body) if inv_refund.payment_term_id.id: inv_refund._onchange_payment_term_date_invoice() created_inv.append(inv_refund.id) xml_id = inv.type == 'out_invoice' and 'action_invoice_out_refund' or \ inv.type == 'out_refund' and 'action_invoice_tree1' or \ inv.type == 'in_invoice' and 'action_invoice_in_refund' or \ inv.type == 'in_refund' and 'action_invoice_tree2' if xml_id: result = self.env.ref('account.%s' % (xml_id)).read()[0] if mode == 'modify': # When refund method is `modify` then it will directly open the new draft bill/invoice in form view if inv_refund.type == 'in_invoice': view_ref = self.env.ref('account.invoice_supplier_form') else: view_ref = self.env.ref('account.invoice_form') result['views'] = [(view_ref.id, 'form')] result['res_id'] = inv_refund.id else: invoice_domain = safe_eval(result['domain']) invoice_domain.append(('id', 'in', created_inv)) result['domain'] = invoice_domain return result return True