From 66b6b5863a15377c91300079026b11e7f81d60e4 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Mon, 14 Jul 2025 14:58:56 +0700 Subject: create bills per receipt --- fixco_custom/models/__init__.py | 1 + fixco_custom/models/detail_order.py | 11 +++- fixco_custom/models/stock_move.py | 39 ++++++++++++ fixco_custom/models/stock_picking.py | 111 +++++++++++++++++++++++++++++++++++ fixco_custom/views/stock_picking.xml | 5 ++ 5 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 fixco_custom/models/stock_move.py diff --git a/fixco_custom/models/__init__.py b/fixco_custom/models/__init__.py index 27178c6..bc53263 100755 --- a/fixco_custom/models/__init__.py +++ b/fixco_custom/models/__init__.py @@ -22,3 +22,4 @@ from . import account_move_line from . import manage_stock from . import automatic_purchase from . import purchasing_job +from . import stock_move \ No newline at end of file diff --git a/fixco_custom/models/detail_order.py b/fixco_custom/models/detail_order.py index 74608b4..8da1c13 100755 --- a/fixco_custom/models/detail_order.py +++ b/fixco_custom/models/detail_order.py @@ -131,9 +131,14 @@ class DetailOrder(models.Model): def process_queue_item_detail(self, limit=100): domain = [ ('execute_status', '=', 'detail_order'), - ('detail_order', 'not like', '"orderStatus": "PENDING_PAYMENT"'), - ('json_ginee', 'not like', '"orderStatus": "PENDING_PAYMENT"') + '|', + ('detail_order', 'not like', '"orderStatus": "PENDING_PAYMENT"'), + ('json_ginee', 'not like', '"orderStatus": "PENDING_PAYMENT"'), + '|', + ('detail_order', 'not like', '"channel":"BLIBLI_ID"'), + ('json_ginee', 'not like', '"channel":"BLIBLI_ID"'), ] + records = self.search(domain, order='create_date desc', limit=limit) for i, rec in enumerate(records, 1): @@ -258,7 +263,7 @@ class DetailOrder(models.Model): return order_lines, product_not_found - def execute_queue_detail(self): + def execute_queue_detail(self): try: json_data = json.loads(self.detail_order) data = self.prepare_data_so(json_data) diff --git a/fixco_custom/models/stock_move.py b/fixco_custom/models/stock_move.py new file mode 100644 index 0000000..1df7af1 --- /dev/null +++ b/fixco_custom/models/stock_move.py @@ -0,0 +1,39 @@ +from odoo import fields, models, api +from odoo.tools.misc import format_date, OrderedSet +from odoo.exceptions import UserError + +class StockMove(models.Model): + _inherit = 'stock.move' + + def _prepare_account_move_line_from_mr(self, po_line, qty, move=False): + po_line.ensure_one() + aml_currency = move and move.currency_id or po_line.currency_id + date = move and move.date or fields.Date.today() + res = { + 'display_type': po_line.display_type, + 'sequence': po_line.sequence, + 'name': '%s: %s' % (po_line.order_id.name, po_line.name), + 'product_id': po_line.product_id.id, + 'product_uom_id': po_line.product_uom.id, + 'quantity': qty, + 'price_unit': po_line.currency_id._convert(po_line.price_unit, aml_currency, po_line.company_id, date, round=False), + 'tax_ids': [(6, 0, po_line.taxes_id.ids)], + 'analytic_account_id': po_line.account_analytic_id.id, + 'analytic_tag_ids': [(6, 0, po_line.analytic_tag_ids.ids)], + 'purchase_line_id': po_line.id, + } + if not move: + return res + + if self.currency_id == move.company_id.currency_id: + currency = False + else: + currency = move.currency_id + + res.update({ + 'move_id': move.id, + 'currency_id': currency and currency.id or False, + 'date_maturity': move.invoice_date_due, + 'partner_id': move.partner_id.id, + }) + return res diff --git a/fixco_custom/models/stock_picking.py b/fixco_custom/models/stock_picking.py index 3beff4a..d38f8a4 100755 --- a/fixco_custom/models/stock_picking.py +++ b/fixco_custom/models/stock_picking.py @@ -44,6 +44,117 @@ class StockPicking(models.Model): store=False ) + def action_create_invoice_from_mr(self): + """Create the invoice associated to the PO. + """ + if self.env.user.id == 13: + 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 self.move_ids_without_package: + po_line = self.env['purchase.order.line'].search( + [('order_id', '=', po.id), ('product_id', '=', line.product_id.id)], limit=1) + qty = line.product_uom_qty + if po_line.display_type == 'line_section': + pending_section = line + continue + if not float_is_zero(po_line.qty_to_invoice, precision_digits=precision): + if pending_section: + invoice_vals['invoice_line_ids'].append( + (0, 0, pending_section._prepare_account_move_line_from_mr(po_line, qty))) + pending_section = None + invoice_vals['invoice_line_ids'].append( + (0, 0, line._prepare_account_move_line_from_mr(po_line, qty))) + 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 + def _compute_pdf_binary(self): for record in self: record.pdf_label_preview = False diff --git a/fixco_custom/views/stock_picking.xml b/fixco_custom/views/stock_picking.xml index c2d899b..c7890f7 100755 --- a/fixco_custom/views/stock_picking.xml +++ b/fixco_custom/views/stock_picking.xml @@ -22,6 +22,11 @@ string="Print Label Ginee" type="object" /> + -- cgit v1.2.3