diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2023-03-21 17:41:29 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2023-03-21 17:41:29 +0700 |
| commit | 768825fb0c1f7d77da1d4689f21bc0473a5085c8 (patch) | |
| tree | d7fb731caa8d33a468d513801e573db73f825172 | |
| parent | 9428bbbaa8161c90b676e3b7980a86b0e8ee5046 (diff) | |
add create bill in goods receipt
| -rw-r--r-- | indoteknik_custom/models/stock_picking.py | 105 | ||||
| -rw-r--r-- | indoteknik_custom/views/stock_picking.xml | 5 |
2 files changed, 110 insertions, 0 deletions
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 5bf774f4..77af676c 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -1,5 +1,7 @@ from odoo import fields, models, api, _ from odoo.exceptions import AccessError, UserError, ValidationError +from odoo.tools.float_utils import float_is_zero +from itertools import groupby class StockPicking(models.Model): @@ -58,6 +60,109 @@ class StockPicking(models.Model): ], string='Approval Return Status', readonly=True, copy=False, index=True, tracking=3, help="Approval Status untuk Return") date_doc_kirim = fields.Datetime(string='Tanggal Kirim di SJ', help="Tanggal Kirim di cetakan SJ, tidak berpengaruh ke Accounting") + def action_create_invoice_from_mr(self): + """Create the invoice associated to the PO. + """ + if not self.env.user.is_accounting: + raise UserError('Hanya Accounting yang bisa membuat Bill') + + precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') + + #custom here + po = self.env['purchase.order'].search([ + ('name', '=', self.group_id.name) + ]) + + # 1) Prepare invoice vals and clean-up the section lines + invoice_vals_list = [] + for order in po: + if order.invoice_status != 'to invoice': + continue + + order = order.with_company(order.company_id) + pending_section = None + # Invoice values. + invoice_vals = order._prepare_invoice() + # Invoice line values (keep only necessary sections). + for line in order.order_line: + if line.display_type == 'line_section': + pending_section = line + continue + if not float_is_zero(line.qty_to_invoice, precision_digits=precision): + if pending_section: + invoice_vals['invoice_line_ids'].append((0, 0, pending_section._prepare_account_move_line())) + pending_section = None + invoice_vals['invoice_line_ids'].append((0, 0, line._prepare_account_move_line())) + invoice_vals_list.append(invoice_vals) + + if not invoice_vals_list: + raise UserError(_('There is no invoiceable line. If a product has a control policy based on received quantity, please make sure that a quantity has been received.')) + + # 2) group by (company_id, partner_id, currency_id) for batch creation + new_invoice_vals_list = [] + for grouping_keys, invoices in groupby(invoice_vals_list, key=lambda x: (x.get('company_id'), x.get('partner_id'), x.get('currency_id'))): + origins = set() + payment_refs = set() + refs = set() + ref_invoice_vals = None + for invoice_vals in invoices: + if not ref_invoice_vals: + ref_invoice_vals = invoice_vals + else: + ref_invoice_vals['invoice_line_ids'] += invoice_vals['invoice_line_ids'] + origins.add(invoice_vals['invoice_origin']) + payment_refs.add(invoice_vals['payment_reference']) + refs.add(invoice_vals['ref']) + ref_invoice_vals.update({ + 'ref': ', '.join(refs)[:2000], + 'invoice_origin': ', '.join(origins), + 'payment_reference': len(payment_refs) == 1 and payment_refs.pop() or False, + }) + new_invoice_vals_list.append(ref_invoice_vals) + invoice_vals_list = new_invoice_vals_list + + # 3) Create invoices. + moves = self.env['account.move'] + AccountMove = self.env['account.move'].with_context(default_move_type='in_invoice') + for vals in invoice_vals_list: + moves |= AccountMove.with_company(vals['company_id']).create(vals) + + # 4) Some moves might actually be refunds: convert them if the total amount is negative + # We do this after the moves have been created since we need taxes, etc. to know if the total + # is actually negative or not + moves.filtered(lambda m: m.currency_id.round(m.amount_total) < 0).action_switch_invoice_into_refund_credit_note() + + return self.action_view_invoice_from_mr(moves) + + def action_view_invoice_from_mr(self, invoices=False): + """This function returns an action that display existing vendor bills of + given purchase order ids. When only one found, show the vendor bill + immediately. + """ + if not invoices: + # Invoice_ids may be filtered depending on the user. To ensure we get all + # invoices related to the purchase order, we read them in sudo to fill the + # cache. + self.sudo()._read(['invoice_ids']) + invoices = self.invoice_ids + + result = self.env['ir.actions.act_window']._for_xml_id('account.action_move_in_invoice_type') + # choose the view_mode accordingly + if len(invoices) > 1: + result['domain'] = [('id', 'in', invoices.ids)] + elif len(invoices) == 1: + res = self.env.ref('account.view_move_form', False) + form_view = [(res and res.id or False, 'form')] + if 'views' in result: + result['views'] = form_view + [(state, view) for state, view in result['views'] if view != 'form'] + else: + result['views'] = form_view + result['res_id'] = invoices.id + else: + result = {'type': 'ir.actions.act_window_close'} + + return result + @api.onchange('date_doc_kirim') def update_date_doc_kirim_so(self): if not self.sale_id: diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml index 866c1aac..0ff79ea8 100644 --- a/indoteknik_custom/views/stock_picking.xml +++ b/indoteknik_custom/views/stock_picking.xml @@ -31,6 +31,11 @@ type="object" attrs="{'invisible': ['|', ('state', '=', 'draft'), ('state', '=', 'cancel'), ('approval_return_status', '=', 'pengajuan1')]}" /> + <button name="action_create_invoice_from_mr" + string="Create Bill" + type="object" + attrs="{'invisible': [('state', '!=', 'done')]}" + /> </button> <field name="backorder_id" position="after"> <field name="is_internal_use" |
