diff options
| author | it-fixcomart <it@fixcomart.co.id> | 2025-09-12 10:49:35 +0700 |
|---|---|---|
| committer | it-fixcomart <it@fixcomart.co.id> | 2025-09-12 10:49:35 +0700 |
| commit | 40229df0261970eb3d955de2651cdb1a997bdbaa (patch) | |
| tree | b50870b51b682097dea6fd92e548268c7ba596a2 | |
| parent | 7d07a282c134cb5e2a784b73cc477e3f398df57c (diff) | |
| parent | 73d249fd48d0aeae8ac77946f07668210e12ae7b (diff) | |
<hafid> fix conflict
| -rw-r--r-- | indoteknik_api/controllers/api_v1/sale_order.py | 213 | ||||
| -rw-r--r-- | indoteknik_api/models/sale_order.py | 14 | ||||
| -rwxr-xr-x | indoteknik_custom/__manifest__.py | 2 | ||||
| -rw-r--r-- | indoteknik_custom/models/account_move.py | 28 | ||||
| -rw-r--r-- | indoteknik_custom/models/approval_payment_term.py | 3 | ||||
| -rwxr-xr-x | indoteknik_custom/models/purchase_order.py | 2 | ||||
| -rw-r--r-- | indoteknik_custom/models/refund_sale_order.py | 1 | ||||
| -rw-r--r-- | indoteknik_custom/models/res_partner.py | 11 | ||||
| -rwxr-xr-x | indoteknik_custom/models/sale_order.py | 45 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_move.py | 3 | ||||
| -rw-r--r-- | indoteknik_custom/report/purchase_report.xml | 162 | ||||
| -rw-r--r-- | indoteknik_custom/views/res_partner.xml | 3 | ||||
| -rwxr-xr-x | indoteknik_custom/views/sale_order.xml | 9 | ||||
| -rw-r--r-- | indoteknik_custom/views/stock_move_line.xml | 9 | ||||
| -rw-r--r-- | indoteknik_custom/views/stock_picking.xml | 105 |
15 files changed, 475 insertions, 135 deletions
diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 65894d8a..accc7531 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -22,7 +22,7 @@ class SaleOrder(controller.Controller): }) sale_order_line = request.env['sale.order.line'].search([ - ('product_id', '=', product_id), + ('product_id', '=', product_id), ('order_id', '=', so_id) ], limit=1) @@ -41,7 +41,7 @@ class SaleOrder(controller.Controller): return self.response('work') else: return self.response('Sale order line not found', status=404) - + @http.route(prefix + "sale_order_number", auth='public', method=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_number_sale_order(self, **kw): @@ -116,14 +116,12 @@ class SaleOrder(controller.Controller): if not params['valid']: return self.response(code=400, description=params) - partner_child_ids = self.get_partner_child_ids( - params['value']['partner_id']) + partner_child_ids = self.get_partner_child_ids(params['value']['partner_id']) domain = [('partner_id', 'in', partner_child_ids)] context = params['value']['context'] if context == 'quotation': - domain += ["|", "|", ("state", "=", "draft"), - ("state", "=", "sent"), ("state", "=", "cancel")] + domain += ["|", "|", ("state", "=", "draft"), ("state", "=", "sent"), ("state", "=", "cancel")] if not context: domain += ["|", ("state", "=", "sale"), ("state", "=", "done")] @@ -135,39 +133,39 @@ class SaleOrder(controller.Controller): ('product_id.name', 'ilike', name), ('product_id.default_code', 'ilike', name), ]) - sale_order_ids_from_lines = order_lines.mapped('order_id.id') - domain += ['|', '|', - ('name', 'ilike', name), - ('partner_purchase_order_name', 'ilike', name), - ('id', 'in', sale_order_ids_from_lines) - ] - + ('name', 'ilike', name), + ('partner_purchase_order_name', 'ilike', name), + ('id', 'in', sale_order_ids_from_lines) + ] + if params['value']['site']: site = params['value']['site'].replace(' ', '%') - domain += [ - ('partner_id.site_id.name', 'ilike', '%' + site + '%') - ] + domain += [('partner_id.site_id.name', 'ilike', '%' + site + '%')] status = params['value'].get('status') if status: if status == 'quotation': domain += [('state', '=', 'draft')] domain += [('approval_status', '=', False)] - elif status == 'cancel': domain += [('state', '=', 'cancel')] - + elif status == 'belum_bayar': + domain += [ + ('state', '=', 'draft'), + ('approval_status', 'in', ['pengajuan1', 'pengajuan2']), + ('payment_status', 'in', [False, None, '', 'pending', 'expire']) + ] elif status == 'diproses': domain += [ ('state', '=', 'draft'), ('approval_status', 'in', ['pengajuan1', 'pengajuan2']), + ('payment_status', '!=', False), + ('payment_status', 'not in', ['', 'pending', 'expire']), ] - elif status in ['dikemas', 'dikirim', 'selesai', 'partial']: domain += [('state', '=', 'sale')] - elif status == 'all': domain += [] @@ -179,7 +177,7 @@ class SaleOrder(controller.Controller): elif params['value']['sort'] == 'desc': order = 'amount_total desc' - # Filter berdasarkan tanggal order + # Filter tanggal try: if params['value']['startDate'] and params['value']['endDate']: start_date = datetime.strptime(params['value']['startDate'], '%d/%m/%Y').strftime('%Y-%m-%d 00:00:00') @@ -190,22 +188,17 @@ class SaleOrder(controller.Controller): domain.append(('date_order', '>=', start_date)) domain.append(('date_order', '<=', end_date)) - except ValueError: return self.response(code=400, description="Invalid date format. Use 'DD/MM/YYYY'.") + sale_orders = request.env['sale.order'].search(domain, order=order) - - sale_orders = request.env['sale.order'].search( - domain, order=order) + # Filter status pengiriman status = params['value'].get('status') if status in ['dikemas', 'dikirim', 'selesai', 'partial']: filtered_orders = [] for sale_order in sale_orders: - bu_pickings = [ - p for p in sale_order.picking_ids - if p.picking_type_id and p.picking_type_id.id == 29 - ] + bu_pickings = [p for p in sale_order.picking_ids if p.picking_type_id and p.picking_type_id.id == 29] total = len(bu_pickings) done_pickings = [p for p in bu_pickings if p.state == 'done'] done_with_driver = [p for p in done_pickings if p.sj_return_date] @@ -213,25 +206,56 @@ class SaleOrder(controller.Controller): if status == 'dikemas' and len(done_pickings) == 0: filtered_orders.append(sale_order) - elif status == 'dikirim' and len(done_pickings) == total and len(done_pickings) > 0 and len(done_without_driver) == total: + elif status == 'dikirim' and len(done_pickings) == total and len(done_pickings) > 0 and len( + done_without_driver) == total: filtered_orders.append(sale_order) - elif status == 'selesai' and len(done_pickings) == total and len(done_pickings) > 0 and len(done_with_driver) == total: + elif status == 'selesai' and len(done_pickings) == total and len(done_pickings) > 0 and len( + done_with_driver) == total: filtered_orders.append(sale_order) elif status == 'partial' and ( - len(done_pickings) != total or - (done_with_driver and done_without_driver) - ): + len(done_pickings) != total or (done_with_driver and done_without_driver)): filtered_orders.append(sale_order) else: filtered_orders = sale_orders filtered_orders_paginated = filtered_orders[offset: offset + limit] + # === Ringkasan (tanpa auto-generate) === + CBD_PAYMENT_TERM_ID = 26 + ALLOWED_CONTINUE = {'', 'pending', 'capture', 'expire', 'cancel'} # boleh munculkan "Bayar Sekarang" + + def _is_website_order(so): + return bool(so.source_id and so.source_id.id == 59) + + sale_orders_payload = [] + for so in filtered_orders_paginated: + item = request.env['sale.order'].api_v1_single_response(so) + + approval_ok = (so.approval_status in ('pengajuan1', 'pengajuan2')) + source_ok = _is_website_order(so) + term_ok = bool(so.payment_term_id and so.payment_term_id.id == CBD_PAYMENT_TERM_ID) + pay_status = (getattr(so, 'payment_status', '') or '').strip().lower() + eligible = bool(approval_ok and source_ok and term_ok and pay_status in ALLOWED_CONTINUE) + + redirect_url = getattr(so, 'payment_link_midtrans', '') or '' + + item.update({ + 'eligibleContinue': eligible, + 'paymentSummary': { + 'eligible': eligible, + 'approvalStatus': so.approval_status or '', + 'paymentStatus': pay_status, + 'paymentTermId': so.payment_term_id.id if so.payment_term_id else None, + 'sourceId': so.source_id.id if so.source_id else None, + 'redirectUrl': redirect_url, + } + }) + sale_orders_payload.append(item) + data = { 'sale_order_total': len(filtered_orders), - 'sale_orders': [request.env['sale.order'].api_v1_single_response(x) for x in filtered_orders_paginated] + 'sale_orders': sale_orders_payload } - return self.response(data) @http.route(PREFIX_PARTNER + 'sale_order/<id>', auth='public', method=['GET', 'OPTIONS']) @@ -240,6 +264,7 @@ class SaleOrder(controller.Controller): params = self.get_request_params(kw, { 'partner_id': ['number'], 'id': ['number'], + 'ensure_payment_link': [], # optional flag }) if not params['valid']: return self.response(code=400, description=params) @@ -247,9 +272,60 @@ class SaleOrder(controller.Controller): partner_child_ids = self.get_partner_child_ids(params['value']['partner_id']) domain = [('id', '=', params['value']['id']), ('partner_id', 'in', partner_child_ids)] data = {} + sale_order = request.env['sale.order'].search(domain) if sale_order: data = request.env['sale.order'].api_v1_single_response(sale_order, context='with_detail') + + CBD_PAYMENT_TERM_ID = 26 + ALLOWED_CONTINUE = {'', 'pending', 'capture', 'expire', 'cancel'} + + def _is_website_order(so): + return bool(so.source_id and so.source_id.id == 59) + + pay_status = (getattr(sale_order, 'payment_status', '') or '').strip().lower() + eligible = ( + sale_order.approval_status in ('pengajuan1', 'pengajuan2') and + _is_website_order(sale_order) and + sale_order.payment_term_id and sale_order.payment_term_id.id == CBD_PAYMENT_TERM_ID and + pay_status in ALLOWED_CONTINUE + ) + + redirect_url = getattr(sale_order, 'payment_link_midtrans', '') or '' + + ensure_raw = params['value'].get('ensure_payment_link') + ensure_flag = False + if ensure_raw is not None: + s = str(ensure_raw).strip().lower() + ensure_flag = s not in ('', '0', 'false', 'no', 'none') + + if ensure_flag and eligible: + should_generate = False + if not redirect_url: + should_generate = True + elif pay_status in ('expire', 'cancel'): + should_generate = True + + if should_generate: + try: + sale_order.sudo().generate_payment_link_midtrans_sales_order() + redirect_url = getattr(sale_order, 'payment_link_midtrans', '') or '' + except Exception as e: + _logger.warning(f'Generate Midtrans gagal untuk SO {sale_order.id}: {e}') + + data.update({ + 'eligible_continue': eligible, + 'payment_summary': { + 'eligible': eligible, + 'approval_status': sale_order.approval_status or '', + 'payment_status': pay_status, + 'payment_term_id': sale_order.payment_term_id.id if sale_order.payment_term_id else None, + 'source_id': sale_order.source_id.id if sale_order.source_id else None, + 'redirect_url': redirect_url, + } + }) + + # formatting tanggal (tetap sama) if sale_order.expected_ready_to_ship: bulan_id = [ "Januari", "Februari", "Maret", "April", "Mei", "Juni", @@ -259,6 +335,7 @@ class SaleOrder(controller.Controller): bulan = bulan_id[sale_order.expected_ready_to_ship.month - 1] tahun = sale_order.expected_ready_to_ship.year data['expected_ready_to_ship'] = f"{tanggal} {bulan} {tahun}" + if sale_order.eta_date_start: bulan_id = [ "Januari", "Februari", "Maret", "April", "Mei", "Juni", @@ -307,12 +384,12 @@ class SaleOrder(controller.Controller): sale_order.approval_status = 'pengajuan2' elif sale_order._requires_approval_margin_manager(): sale_order.approval_status = 'pengajuan1' - + data = request.env['sale.order'].api_v1_single_response( sale_order, context='with_detail') return self.response(data) - + @http.route(PREFIX_PARTNER + 'sale_order/<id>/approve', auth='public', method=['POST', 'OPTIONS'], csrf=False) @controller.Controller.must_authorized(private=True, private_key='partner_id') def partner_approve_sale_order_by_id(self, **kw): @@ -320,27 +397,27 @@ class SaleOrder(controller.Controller): 'partner_id': ['number'], 'id': ['number'] }) - + if not params['valid']: return self.response(code=400, description=params) - + value = params['value'] partner_child_ids = self.get_partner_child_ids(value['partner_id']) - + sale_order = request.env['sale.order'].search([ ('id', '=', value['id']), ('partner_id', 'in', partner_child_ids) ]) if not sale_order: return self.response(code=404, description='Sale Order not found') - + partner = request.env['res.partner'].browse(value['partner_id']) if not partner.web_role: return self.response(code=400, description='Unauthorized') - + if partner.web_role: sale_order.web_approval = 'cust_%s' % partner.web_role - + if sale_order.web_approval in ['cust_procurement', 'cust_director']: if sale_order._requires_approval_margin_leader(): sale_order.approval_status = 'pengajuan2' @@ -348,7 +425,7 @@ class SaleOrder(controller.Controller): sale_order.approval_status = 'pengajuan1' return self.response('success') - + @http.route(PREFIX_PARTNER + 'sale_order/<id>/reject', auth='public', method=['POST', 'OPTIONS'], csrf=False) @controller.Controller.must_authorized(private=True, private_key='partner_id') def partner_reject_sale_order_by_id(self, **kw): @@ -356,27 +433,27 @@ class SaleOrder(controller.Controller): 'partner_id': ['number'], 'id': ['number'] }) - + if not params['valid']: return self.response(code=400, description=params) - + value = params['value'] partner_child_ids = self.get_partner_child_ids(value['partner_id']) - + sale_order = request.env['sale.order'].search([ ('id', '=', value['id']), ('partner_id', 'in', partner_child_ids) ]) if not sale_order: return self.response(code=404, description='Sale Order not found') - + partner = request.env['res.partner'].browse(value['partner_id']) if not partner.web_role: return self.response(code=400, description='Unauthorized') - + if partner.web_role: sale_order.web_approval = 'cust_%s' % partner.web_role - + sale_order.state = 'cancel' sale_order.approval_status = False @@ -447,7 +524,7 @@ class SaleOrder(controller.Controller): sale_order = request.env['sale.order'].sudo().search_read([('id', '=', id)], ['name']) # pdf, type = request.env['ir.actions.report'].sudo().search([('report_name', '=', 'quotation_so_new')]).render_jasper([id], {}) pdf, type = request.env['ir.actions.report'].sudo().search([('report_name', '=', 'indoteknik_custom.report_saleorder_website')])._render_qweb_pdf([id]) - + if pdf and len(sale_order) > 0: return rest_api.response_attachment({ 'content': pdf, @@ -478,27 +555,27 @@ class SaleOrder(controller.Controller): sale_order.state = 'cancel' data = sale_order.id return self.response(data) - + @http.route(prefix + 'user/<user_id>/sale_order/checkout', auth='public', method=['GET', 'OPTIONS'], csrf=False) @controller.Controller.must_authorized(private=True, private_key='user_id') def get_user_checkout_so(self, user_id, **kw): m_voucher = request.env['voucher'] m_cart = request.env['website.user.cart'] - + voucher_code = kw.get('voucher') voucher_shipping_code = kw.get('voucher_shipping') source = kw.get('source') - + voucher = m_voucher.search([('code', '=', voucher_code), ('apply_type', 'in', ['all', 'brand'])], limit=1) voucher_shipping = m_voucher.search([('code', '=', voucher_shipping_code), ('apply_type', '=', 'shipping')], limit=1) result = m_cart.with_context(price_for="web").get_user_checkout( - user_id, - voucher=voucher, - voucher_shipping=voucher_shipping, + user_id, + voucher=voucher, + voucher_shipping=voucher_shipping, source=source ) return self.response(result) - + @http.route(PREFIX_PARTNER + 'sale_order/checkout', auth='public', method=['POST', 'OPTIONS'], csrf=False) @controller.Controller.must_authorized() def create_partner_sale_order(self, **kw): @@ -544,7 +621,7 @@ class SaleOrder(controller.Controller): main_partner = partner_invoice.get_main_parent() _logger.info( f"Partner Info - Sales: {sales_partner.id}, Invoice: {partner_invoice.id}, Main: {main_partner.id}") - + def _get_request_context(params, kw): # 1) kw (querystring di route) ctx = kw.get('context') @@ -582,7 +659,7 @@ class SaleOrder(controller.Controller): f"form={repr(request.httprequest.form.get('context'))}, " f"json={(request.httprequest.get_json(force=False, silent=True) or {}).get('context') if hasattr(request.httprequest,'get_json') else None}, " f"normalized={ctx}") - + payment_term_id_value = 26 ctx = str((kw.get('context') or '')) @@ -607,7 +684,7 @@ class SaleOrder(controller.Controller): payment_term_id_value = term.id except Exception as e: _logger.warning(f"Gagal resolve payment term dari user: {e}") - + parameters = { 'warehouse_id': 8, 'carrier_id': 1, @@ -767,7 +844,7 @@ class SaleOrder(controller.Controller): except Exception as e: _logger.error(f"Error in create_partner_sale_order: {str(e)}", exc_info=True) return self.response(code=500, description=str(e)) - + @http.route(PREFIX_PARTNER + 'sale-order/<id>/awb', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized(private=True, private_key='partner_id') def get_airway_bill_by_sale_order_id(self, **kw): @@ -782,8 +859,8 @@ class SaleOrder(controller.Controller): for airway_bill in airway_bills: data = airway_bill.decode_response() delivery_order = airway_bill.do_id - result = data['rajaongkir']['result'] - + result = data['rajaongkir']['result'] + manifests_data = [] for manifest in airway_bill.manifest_ids: manifest_data = { @@ -793,7 +870,7 @@ class SaleOrder(controller.Controller): 'city': manifest.city, } manifests_data.append(manifest_data) - + airways.append({ 'delivery_order': { 'name': delivery_order.name, @@ -801,7 +878,7 @@ class SaleOrder(controller.Controller): 'receiver_name': airway_bill.receiver_name, 'receiver_city': airway_bill.receiver_city, }, - 'delivered': result['delivered'], + 'delivered': result['delivered'], 'waybill_number': result['summary']['waybill_number'], 'delivery_status': result['delivery_status'], 'manifests': manifests_data @@ -809,7 +886,7 @@ class SaleOrder(controller.Controller): response = {'airways': airways} return self.response(response) - + @http.route('/api/sale_order/invoiced', auth='public', methods=['GET']) def get_sale_order_invoiced_by_partner_id(self, **kw): if not self.authenticate(): diff --git a/indoteknik_api/models/sale_order.py b/indoteknik_api/models/sale_order.py index 9be03927..c59dead9 100644 --- a/indoteknik_api/models/sale_order.py +++ b/indoteknik_api/models/sale_order.py @@ -60,13 +60,17 @@ class SaleOrder(models.Model): # 'tracking_number': picking.delivery_tracking_no or '', # 'delivered': picking.waybill_id.delivered or picking.driver_arrival_date != False or picking.sj_return_date != False, }) + if sale_order.state == 'cancel': data['status'] = 'cancel' - if sale_order.state == 'draft' and sale_order.approval_status == False: - data['status'] = 'draft' - if sale_order.state == 'draft' and sale_order.approval_status in ['pengajuan1', 'pengajuan2']: - data['status'] = 'waiting' - + elif sale_order.state == 'draft': + if not sale_order.approval_status: + data['status'] = 'draft' + elif sale_order.approval_status in ('pengajuan1', 'pengajuan2'): + if sale_order.payment_status in ('', 'pending', False, None, 'expire'): + data['status'] = 'belum_bayar' + elif sale_order.payment_status not in ['', 'pending', False, None, 'expire']: + data['status'] = 'waiting' if sale_order.state == 'sale': bu_pickings = [ diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index 31685005..09a3aa6f 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -166,6 +166,7 @@ 'report/report_invoice.xml', 'report/report_picking.xml', 'report/report_sale_order.xml', + 'report/purchase_report.xml', 'views/vendor_sla.xml', 'views/coretax_faktur.xml', 'views/public_holiday.xml', @@ -177,6 +178,7 @@ 'views/tukar_guling_po.xml', # 'views/refund_sale_order.xml', 'views/update_date_planned_po_wizard_view.xml', + # 'views/reimburse.xml', ], 'demo': [], 'css': [], diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index c93cfb76..70cd07e4 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -105,6 +105,34 @@ class AccountMove(models.Model): tracking=True ) + # def _check_and_lock_cbd(self): + # cbd_term = self.env['account.payment.term'].browse(26) + # today = date.today() + + # # Cari semua invoice overdue + # overdue_invoices = self.search([ + # ('move_type', '=', 'out_invoice'), + # ('state', '=', 'posted'), + # ('payment_state', 'not in', ['paid', 'in_payment', 'reversed']), + # ('invoice_date_due', '!=', False), + # ('invoice_date_due', '<=', today - timedelta(days=30)), + # ], limit=3) + + # _logger.info(f"Found {len(overdue_invoices)} overdue invoices for CBD lock check.") + # _logger.info(f"Overdue Invoices: {overdue_invoices.mapped('name')}") + + # # Ambil partner unik dari invoice + # partners_to_lock = overdue_invoices.mapped('partner_id').filtered(lambda p: not p.is_cbd_locked) + # _logger.info(f"Partners to lock: {partners_to_lock.mapped('name')}") + + # # Lock hanya partner yang belum locked + # if partners_to_lock: + # partners_to_lock.write({ + # 'is_cbd_locked': True, + # 'property_payment_term_id': cbd_term.id, + # }) + + def compute_partial_payment(self): for move in self: if move.amount_total_signed > 0 and move.amount_residual_signed > 0 and move.payment_state == 'partial': diff --git a/indoteknik_custom/models/approval_payment_term.py b/indoteknik_custom/models/approval_payment_term.py index 8618856a..08d91738 100644 --- a/indoteknik_custom/models/approval_payment_term.py +++ b/indoteknik_custom/models/approval_payment_term.py @@ -171,7 +171,8 @@ class ApprovalPaymentTerm(models.Model): 'blocking_stage': self.blocking_stage, 'warning_stage': self.warning_stage, 'active_limit': self.active_limit, - 'property_payment_term_id': self.property_payment_term_id.id + 'property_payment_term_id': self.property_payment_term_id.id, + 'is_locked_cbd': False, }) self.approve_date = datetime.utcnow() self.state = 'approved' diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py index 50913a80..18811b85 100755 --- a/indoteknik_custom/models/purchase_order.py +++ b/indoteknik_custom/models/purchase_order.py @@ -66,7 +66,7 @@ class PurchaseOrder(models.Model): sale_order = fields.Char(string='Sale Order') matches_so = fields.Many2many('sale.order', string='Matches SO', compute='_compute_matches_so') is_create_uangmuka = fields.Boolean(string='Uang Muka?') - move_id = fields.Many2one('account.move', string='Journal Entries Uang Muka', domain=[('move_type', '=', 'entry')]) + move_id = fields.Many2one('account.move', string='Journal Entries Uang Muka', domain=[('move_type', '=', 'entry')], copy=False) logbook_bill_id = fields.Many2one('report.logbook.bill', string='Logbook Bill') status_printed = fields.Selection([ ('not_printed', 'Belum Print'), diff --git a/indoteknik_custom/models/refund_sale_order.py b/indoteknik_custom/models/refund_sale_order.py index e981abb5..9bcdd974 100644 --- a/indoteknik_custom/models/refund_sale_order.py +++ b/indoteknik_custom/models/refund_sale_order.py @@ -76,6 +76,7 @@ class RefundSaleOrder(models.Model): transfer_move_id = fields.Many2one( 'account.move', string="Journal Payment", + copy=False, help="Pilih transaksi salah transfer dari jurnal Uang Muka (journal_id=11) yang tidak terkait SO." ) diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py index 148a3fd0..36570e8f 100644 --- a/indoteknik_custom/models/res_partner.py +++ b/indoteknik_custom/models/res_partner.py @@ -1,6 +1,6 @@ from odoo import models, fields, api from odoo.exceptions import UserError, ValidationError -from datetime import datetime +from datetime import datetime, timedelta from odoo.http import request import re import requests @@ -181,10 +181,8 @@ class ResPartner(models.Model): payment_difficulty = fields.Selection([('bermasalah', 'Bermasalah'),('sulit', 'Sulit'),('agak_sulit', 'Agak Sulit'),('normal', 'Normal')], string='Payment Difficulty', tracking=3) payment_history_url = fields.Text(string='Payment History URL') - # no compute - # payment_diff = fields.Selection([('bermasalah', 'Bermasalah'),('sulit', 'Sulit'),('agak_sulit', 'Agak Sulit'),('normal', 'Normal')], string='Payment Difficulty', tracking=3) - - # tidak terpakai + is_cbd_locked = fields.Boolean("Locked to CBD?", default=False, tracking=True, help="Jika dicentang, maka partner ini terkunci pada payment term CBD karena memiliki invoice yang sudah jatuh tempo lebih dari 30 hari.") + @api.model def _default_payment_term(self): @@ -193,9 +191,10 @@ class ResPartner(models.Model): property_payment_term_id = fields.Many2one( 'account.payment.term', string='Payment Terms', - default=_default_payment_term + default=_default_payment_term, tracking=3 ) + @api.depends("street", "street2", "city", "state_id", "country_id", "blok", "nomor", "rt", "rw", "kelurahan_id", "kecamatan_id") def _alamat_lengkap_text(self): diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 903f834b..76d4d7e7 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -393,6 +393,26 @@ class SaleOrder(models.Model): ('paid', 'Full Paid'), ('no_invoice', 'No Invoice'), ], string="Payment Status Invoice", compute="_compute_payment_state_custom", store=False) + partner_is_cbd_locked = fields.Boolean( + string="Partner Locked CBD", + compute="_compute_partner_is_cbd_locked" + ) + + @api.depends('partner_id.is_cbd_locked') + def _compute_partner_is_cbd_locked(self): + for order in self: + order.partner_is_cbd_locked = order.partner_id.is_cbd_locked + + + @api.constrains('payment_term_id', 'partner_id', 'state') + def _check_cbd_lock_sale_order(self): + # cbd_term = self.env['account.payment.term'].browse(26) + for rec in self: + if rec.state == 'draft' and rec.partner_id.is_cbd_locked: + # if rec.payment_term_id and rec.payment_term_id != cbd_term: + raise ValidationError( + "Customer ini terkunci ke CBD, hanya boleh pakai Payment Term CBD." + ) @api.depends('invoice_ids.payment_state', 'invoice_ids.amount_total', 'invoice_ids.amount_residual') def _compute_payment_state_custom(self): @@ -1899,26 +1919,30 @@ class SaleOrder(models.Model): # raise UserError('Kelurahan Real Delivery Address harus diisi') def generate_payment_link_midtrans_sales_order(self): - # midtrans_url = 'https://app.sandbox.midtrans.com/snap/v1/transactions' # dev - sandbox - # midtrans_auth = 'Basic U0ItTWlkLXNlcnZlci1uLVY3ZDJjMlpCMFNWRUQyOU95Q1dWWXA6' # dev - sandbox - midtrans_url = 'https://app.midtrans.com/snap/v1/transactions' # production - midtrans_auth = 'Basic TWlkLXNlcnZlci1SbGMxZ2gzWGpSVW5scl9JblZzTV9OTnU6' # production + # midtrans_url = 'https://app.sandbox.midtrans.com/snap/v1/transactions' # dev - sandbox + # midtrans_auth = 'Basic U0ItTWlkLXNlcnZlci1uLVY3ZDJjMlpCMFNWRUQyOU95Q1dWWXA6' # dev - sandbox + midtrans_url = 'https://app.midtrans.com/snap/v1/transactions' # production + midtrans_auth = 'Basic TWlkLXNlcnZlci1SbGMxZ2gzWGpSVW5scl9JblZzTV9OTnU6' # production + so_number = self.name so_number = so_number.replace('/', '-') so_grandtotal = math.floor(self.grand_total) + headers = { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': midtrans_auth, } - check_url = f'https://api.midtrans.com/v2/{so_number}/status' - check_response = requests.get(check_url, headers=headers) + # ==== ENV ==== + # check_url = f'https://api.sandbox.midtrans.com/v2/{so_number}/status' # dev - sandbox + check_url = f'https://api.midtrans.com/v2/{so_number}/status' # production + # ============================================= + check_response = requests.get(check_url, headers=headers) if check_response.status_code == 200: status_response = check_response.json() - if status_response.get('transaction_status') == 'expire' or status_response.get( - 'transaction_status') == 'cancel': + if status_response.get('transaction_status') in ('expire', 'cancel'): so_number = so_number + '-cpl' json_data = { @@ -1950,7 +1974,6 @@ class SaleOrder(models.Model): buffer = BytesIO() img.save(buffer, format="PNG") qr_code_img = base64.b64encode(buffer.getvalue()).decode() - self.payment_qr_code = qr_code_img @api.model @@ -2112,8 +2135,8 @@ class SaleOrder(models.Model): if self.payment_term_id.id == 31 and self.total_percent_margin < 25: raise UserError("Jika ingin menggunakan Tempo 90 Hari maka margin harus di atas 25%") - if self.warehouse_id.id != 8 and self.warehouse_id.id != 10: # GD Bandengan - raise UserError('Gudang harus Bandengan') + if self.warehouse_id.id != 8 and self.warehouse_id.id != 10 and self.warehouse_id.id != 12: # GD Bandengan / Pameran + raise UserError('Gudang harus Bandengan atau Pameran') if self.state not in ['draft', 'sent']: raise UserError("Status harus draft atau sent") diff --git a/indoteknik_custom/models/stock_move.py b/indoteknik_custom/models/stock_move.py index 64cb6ba6..d6505a86 100644 --- a/indoteknik_custom/models/stock_move.py +++ b/indoteknik_custom/models/stock_move.py @@ -1,6 +1,9 @@ from odoo import fields, models, api from odoo.tools.misc import format_date, OrderedSet from odoo.exceptions import UserError +import logging + +_logger = logging.getLogger(__name__) class StockMove(models.Model): _inherit = 'stock.move' diff --git a/indoteknik_custom/report/purchase_report.xml b/indoteknik_custom/report/purchase_report.xml new file mode 100644 index 00000000..9d7f4028 --- /dev/null +++ b/indoteknik_custom/report/purchase_report.xml @@ -0,0 +1,162 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <data> + <!-- Report Action --> + <record id="action_report_purchaseorder_website" model="ir.actions.report"> + <field name="name">Purchase Order (Website)</field> + <field name="model">purchase.order</field> + <field name="report_type">qweb-pdf</field> + <field name="report_name">indoteknik_custom.report_purchaseorder_website</field> + <field name="report_file">indoteknik_custom.report_purchaseorder_website</field> + <field name="print_report_name"> + ('PO - %s - %s' % (object.partner_id.name, object.name)) + </field> + <field name="binding_model_id" ref="purchase.model_purchase_order"/> + <field name="binding_type">report</field> + </record> + </data> + + <!-- Wrapper Template --> + <template id="report_purchaseorder_website"> + <t t-call="web.html_container"> + <t t-foreach="docs" t-as="doc"> + <t t-call="indoteknik_custom.report_purchaseorder_website_document" t-lang="doc.partner_id.lang"/> + </t> + </t> + </template> + + <!-- Document Template --> +<template id="report_purchaseorder_website_document"> + <t t-call="web.external_layout"> + <t t-set="doc" t-value="doc.with_context(lang=doc.partner_id.lang)" /> + + <div class="page"> + <!-- Header Image --> + <div class="mb16"> + <img src="https://erp.indoteknik.com/api/image/ir.attachment/datas/2498521" + style="width:100%; max-height:100px; object-fit:contain;"/> + </div> + + <!-- Title --> + <h2 class="text-center mb4" style="color:#d32f2f; font-weight:bold;"> + PURCHASE ORDER + </h2> + <h4 class="text-center mb32"> + No. <span t-field="doc.name"/> + </h4> + + <!-- Top Info sejajar --> + <div class="row mb16" style="font-size:12px;"> + <div class="col-4"> + <strong>Term Of Payment:</strong> + <span t-field="doc.payment_term_id.name"/> + </div> + <div class="col-4"> + <strong>Order Date:</strong> + <span t-field="doc.date_order" t-options='{"widget": "date"}'/> + </div> + <div class="col-4"> + <strong>Responsible:</strong> + <span t-field="doc.user_id"/> + </div> + </div> + + <!-- Vendor & Shipping Info sejajar --> + <div class="row mb32" style="font-size:12px;"> + <div class="col-6" style="border:1px solid #ccc; padding:8px;"> + <strong>Alamat Pengiriman:</strong><br/> + PT Indoteknik (Bandengan 1 Depan)<br/> + Jl. Bandengan Utara Komp A 8 B<br/> + RT. Penjaringan, Kec. Penjaringan, Jakarta (BELAKANG INDOMARET)<br/> + JK 14440<br/> + Indonesia + </div> + <div class="col-6" style="border:1px solid #ccc; padding:8px;"> + <strong>Nama Vendor:</strong><br/> + <div t-field="doc.partner_id" + t-options='{"widget": "contact", "fields": ["address", "name", "phone"], + "no_marker": True, "phone_icons": True}'/> + </div> + </div> + + <!-- Order Lines --> + <table class="table table-sm o_main_table" style="font-size:11px; border:1px solid #000; border-collapse: collapse; width:100%;"> + <thead style="display: table-row-group; background:#f5f5f5;"> + <tr> + <th style="border:1px solid #000; padding:4px;">Description</th> + <th class="text-right" style="border:1px solid #000; padding:4px;">Quantity</th> + <th class="text-right" style="border:1px solid #000; padding:4px;">Unit Price</th> + <th class="text-right" style="border:1px solid #000; padding:4px;">Taxes</th> + <th class="text-right" style="border:1px solid #000; padding:4px;">Subtotal</th> + </tr> + </thead> + <tbody> + <t t-foreach="doc.order_line" t-as="line"> + <!-- Main row --> + <tr> + <td style="border:1px solid #000; padding:4px;"> + <span t-field="line.name"/> + </td> + <td class="text-right" style="border:1px solid #000; padding:4px;"> + <span t-field="line.product_qty"/> + <span t-field="line.product_uom"/> + </td> + <td class="text-right" style="border:1px solid #000; padding:4px;"> + <span t-field="line.price_unit"/> + </td> + <td class="text-right" style="border:1px solid #000; padding:4px;"> + <span t-esc="', '.join(map(lambda x: (x.description or x.name), line.taxes_id))"/> + </td> + <td class="text-right" style="border:1px solid #000; padding:4px;"> + <span t-field="line.price_subtotal"/> + </td> + </tr> + <!-- Website Description row --> + <t t-if="line.product_id.website_description"> + <tr> + <td colspan="5" style="border:1px solid #000; padding:6px; font-size:10px; color:#555;"> + <div t-raw="line.product_id.website_description"/> + </td> + </tr> + </t> + </t> + </tbody> + </table> + + <!-- Totals --> + <div class="clearfix"> + <div class="row"> + <div class="col-4 ml-auto"> + <table class="table table-sm" style="border:1px solid #000; border-collapse: collapse; width:100%;"> + <tr> + <td style="border:1px solid #000; padding:4px;"><strong>Subtotal</strong></td> + <td class="text-right" style="border:1px solid #000; padding:4px;"> + <span t-field="doc.amount_untaxed"/> + </td> + </tr> + <tr> + <td style="border:1px solid #000; padding:4px;">Taxes</td> + <td class="text-right" style="border:1px solid #000; padding:4px;"> + <span t-field="doc.amount_tax"/> + </td> + </tr> + <tr class="o_total"> + <td style="border:1px solid #000; padding:4px;"><strong>Total</strong></td> + <td class="text-right" style="border:1px solid #000; padding:4px;"> + <span t-field="doc.amount_total"/> + </td> + </tr> + </table> + </div> + </div> + </div> + + <!-- Notes --> + <div class="mt32" style="font-size:11px;"> + <p t-field="doc.notes"/> + </div> + </div> + </t> + </template> + +</odoo> diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml index ca1a36de..7d5be3b7 100644 --- a/indoteknik_custom/views/res_partner.xml +++ b/indoteknik_custom/views/res_partner.xml @@ -21,6 +21,7 @@ <field name="reference_number"/> </field> <field name="property_payment_term_id" position="after"> + <field name="is_cbd_locked" readonly="1"/> <field name="user_payment_terms_sales" readonly="1"/> <field name="date_payment_terms_sales" readonly="1"/> </field> @@ -107,7 +108,7 @@ <field name="reminder_invoices"/> </xpath> <xpath expr="//field[@name='property_payment_term_id']" position="attributes"> - <attribute name="readonly">0</attribute> + <attribute name="readonly">1</attribute> </xpath> <xpath expr="//field[@name='property_supplier_payment_term_id']" position="attributes"> <attribute name="readonly">1</attribute> diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index 156c48d7..326fd560 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -41,6 +41,15 @@ string="Refund" class="btn-primary" /> </xpath> + <xpath expr="//sheet" position="before"> + <field name="partner_is_cbd_locked" invisible="1"/> + <div class="alert alert-danger" + role="alert" + style="height: 40px; margin-bottom:0px;" + attrs="{'invisible':['|', ('partner_is_cbd_locked','=',False), ('state', 'not in', ['draft', 'cancel'])]}"> + <strong>Warning!</strong> Payment Terms Customer terkunci menjadi <b>Cash Before Delivery (C.B.D.)</b> karena ada invoice telah jatuh tempo <b>30 hari</b>. Silakan ajukan <b>Approval Payment Term</b> untuk membuka kunci. + </div> + </xpath> <div class="oe_button_box" name="button_box"> <field name="advance_payment_move_ids" invisible="1"/> <button name="action_open_advance_payment_moves" diff --git a/indoteknik_custom/views/stock_move_line.xml b/indoteknik_custom/views/stock_move_line.xml index 757d2522..94c0bf53 100644 --- a/indoteknik_custom/views/stock_move_line.xml +++ b/indoteknik_custom/views/stock_move_line.xml @@ -3,18 +3,19 @@ <record id="stock_move_line_form_view_inherited" model="ir.ui.view"> <field name="name">Stock Move Line</field> <field name="model">stock.move.line</field> - <field name="inherit_id" ref="stock.view_move_line_form" /> + <field name="inherit_id" ref="stock.view_move_line_form"/> + <field name="priority" eval="100"/> <field name="arch" type="xml"> - <field name="qty_done" position="after"> + <xpath expr="(//form//group[.//field[@name='qty_done']])[last()]" position="inside"> <field name="manufacture"/> - </field> + </xpath> </field> </record> <record id="stock_move_line_tree_view_inherited" model="ir.ui.view"> <field name="name">Stock Move Line</field> <field name="model">stock.move.line</field> - <field name="inherit_id" ref="stock.view_move_line_tree" /> + <field name="inherit_id" ref="stock.view_move_line_tree"/> <field name="arch" type="xml"> <field name="product_id" position="after"> <field name="manufacture"/> diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml index b3f0ce9f..fc8be790 100644 --- a/indoteknik_custom/views/stock_picking.xml +++ b/indoteknik_custom/views/stock_picking.xml @@ -8,7 +8,7 @@ <field name="arch" type="xml"> <tree position="attributes"> <attribute name="default_order">final_seq asc</attribute> - <!-- <attribute name="default_order">create_date desc</attribute> --> + <!-- <attribute name="default_order">create_date desc</attribute> --> </tree> <field name="json_popover" position="after"> <field name="date_done" optional="hide"/> @@ -20,9 +20,11 @@ <field name="sj_return_date" optional="hide"/> <field name="date_reserved" optional="hide"/> <field name="state_reserve" optional="hide"/> - <field name="state_packing" widget="badge" decoration-success="state_packing == 'packing_done'" decoration-danger="state_packing == 'not_packing'" optional="hide"/> + <field name="state_packing" widget="badge" decoration-success="state_packing == 'packing_done'" + decoration-danger="state_packing == 'not_packing'" optional="hide"/> <field name="final_seq"/> - <field name="state_approve_md" widget="badge" decoration-success="state_approve_md == 'done'" decoration-warning="state_approve_md == 'pending'" optional="hide"/> + <field name="state_approve_md" widget="badge" decoration-success="state_approve_md == 'done'" + decoration-warning="state_approve_md == 'pending'" optional="hide"/> <!-- <field name="countdown_hours" optional="hide"/> <field name="countdown_ready_to_ship" /> --> </field> @@ -50,11 +52,11 @@ type="object" attrs="{'invisible': ['|', ('state', 'in', ['done']), ('approval_receipt_status', '=', 'pengajuan1')]}" /> -<!-- <button name="ask_return_approval"--> -<!-- string="Ask Return/Acc"--> -<!-- type="object"--> -<!-- attrs="{'invisible': [('state', 'in', ['draft', 'cancel', 'assigned'])]}"--> -<!-- />--> + <!-- <button name="ask_return_approval"--> + <!-- string="Ask Return/Acc"--> + <!-- type="object"--> + <!-- attrs="{'invisible': [('state', 'in', ['draft', 'cancel', 'assigned'])]}"--> + <!-- />--> <button name="action_create_invoice_from_mr" string="Create Bill" type="object" @@ -64,12 +66,12 @@ string="Biteship" type="object" /> - <!-- <button name="action_sync_biteship_tracking" - type="object" - string="Lacak dari Biteship" - class="btn-primary" - attrs="{'invisible': [('biteship_id', '=', False)]}" - /> --> + <!-- <button name="action_sync_biteship_tracking" + type="object" + string="Lacak dari Biteship" + class="btn-primary" + attrs="{'invisible': [('biteship_id', '=', False)]}" + /> --> <button name="track_envio_shipment" string="Tracking Envio" type="object" @@ -97,6 +99,11 @@ attrs="{'invisible': [('state_approve_md', 'not in', ['waiting'])]}" /> </button> + <!-- <xpath expr="//field[@name='move_ids_without_package']//tree//field[@name='product_uom']" + position="after"> + <field name="product_image" widget="image" + style="height:128px;width:128px;" readonly="1"/> + </xpath> --> <field name="backorder_id" position="after"> <field name="select_shipping_option_so"/> <field name="shipping_method_so_id"/> @@ -105,7 +112,8 @@ <field name="count_line_detail"/> <field name="dokumen_tanda_terima"/> <field name="dokumen_pengiriman"/> - <field name="quantity_koli" attrs="{'invisible': [('location_dest_id', '!=', 60)], 'required': [('location_dest_id', '=', 60)]}"/> + <field name="quantity_koli" + attrs="{'invisible': [('location_dest_id', '!=', 60)], 'required': [('location_dest_id', '=', 60)]}"/> <field name="total_mapping_koli" attrs="{'invisible': [('location_id', '!=', 60)]}"/> <field name="total_koli_display" readonly="1" attrs="{'invisible': [('location_id', '!=', 60)]}"/> <field name="linked_out_picking_id" readonly="1" attrs="{'invisible': [('location_id', '=', 60)]}"/> @@ -132,8 +140,13 @@ <field name="scheduled_date" position="attributes"> <attribute name="readonly">1</attribute> </field> + <xpath expr="//field[@name='move_ids_without_package']/form/group/field[@name='description_picking']" + position="after"> + <field name="product_image" widget="image" string="Product Image"/> + </xpath> + <field name="origin" position="after"> -<!-- <field name="show_state_approve_md" invisible="1" optional="hide"/>--> + <!-- <field name="show_state_approve_md" invisible="1" optional="hide"/>--> <field name="state_approve_md" widget="badge"/> <field name="purchase_id"/> <field name="sale_order"/> @@ -141,7 +154,8 @@ <field name="date_doc_kirim" attrs="{'readonly':[('invoice_status', '=', 'invoiced')]}"/> <field name="summary_qty_operation"/> <field name="count_line_operation"/> - <field name="linked_manual_bu_out" attrs="{'invisible': [('location_id', '=', 60)]}" domain="[('picking_type_code', '=', 'outgoing'),('state', 'not in', ['done','cancel']), ('group_id', '=', group_id)]"/> + <field name="linked_manual_bu_out" attrs="{'invisible': [('location_id', '=', 60)]}" + domain="[('picking_type_code', '=', 'outgoing'),('state', 'not in', ['done','cancel']), ('group_id', '=', group_id)]"/> <field name="account_id" attrs="{ 'readonly': [['state', 'in', ['done', 'cancel']]], @@ -189,29 +203,35 @@ </group> </group> </page> - <page string="Delivery" name="delivery_order" attrs="{'invisible': [('location_dest_id', '=', 60)]}"> + <page string="Delivery" name="delivery_order" + attrs="{'invisible': [('location_dest_id', '=', 60)]}"> <group> <group> <field name="notee"/> <field name="note_logistic"/> <field name="note_info"/> - <field name="responsible" /> - <field name="carrier_id" attrs="{'invisible': [('select_shipping_option_so', '=', 'biteship')]}" /> + <field name="responsible"/> + <field name="carrier_id" + attrs="{'invisible': [('select_shipping_option_so', '=', 'biteship')]}"/> <field name="biteship_id" invisible="1"/> <field name="out_code" attrs="{'invisible': [['out_code', '=', False]]}"/> <field name="picking_code" attrs="{'invisible': [['picking_code', '=', False]]}"/> - <field name="picking_code" string="Picking code (akan digenerate ketika sudah di-validate)" attrs="{'invisible': [['picking_code', '!=', False]]}"/> - <field name="driver_departure_date" attrs="{'readonly':[('invoice_status', '=', 'invoiced')]}"/> + <field name="picking_code" + string="Picking code (akan digenerate ketika sudah di-validate)" + attrs="{'invisible': [['picking_code', '!=', False]]}"/> + <field name="driver_departure_date" + attrs="{'readonly':[('invoice_status', '=', 'invoiced')]}"/> <field name="driver_arrival_date"/> - <field name="delivery_tracking_no" attrs="{'invisible': [('select_shipping_option_so', '=', 'biteship')]}"/> + <field name="delivery_tracking_no" + attrs="{'invisible': [('select_shipping_option_so', '=', 'biteship')]}"/> <field name="driver_id"/> <field name='sj_return_date'/> - <field name="sj_documentation" widget="image" /> - <field name="paket_documentation" widget="image" /> + <field name="sj_documentation" widget="image"/> + <field name="paket_documentation" widget="image"/> </group> <!-- Biteship Group --> <group attrs="{'invisible': [('select_shipping_option_so', '!=', 'biteship')]}"> - <field name="delivery_tracking_no" /> + <field name="delivery_tracking_no"/> <field name="shipping_method_so_id"/> <field name="shipping_option_so_id"/> <field name="biteship_shipping_price" readonly="1"/> @@ -220,7 +240,8 @@ <field name="biteship_driver_name" readonly="1"/> <field name="biteship_driver_phone" readonly="1"/> <field name="biteship_driver_plate_number" readonly="1"/> - <button name="action_open_biteship_tracking" string="Visit Biteship Tracking" type="object"/> + <button name="action_open_biteship_tracking" string="Visit Biteship Tracking" + type="object"/> </group> <group attrs="{'invisible': [('carrier_id', '!=', 151)]}"> @@ -261,23 +282,27 @@ </group> </group> </page> - <page string="Check Product" name="check_product" attrs="{'invisible': [('picking_type_code', '=', 'outgoing')]}"> + <page string="Check Product" name="check_product" + attrs="{'invisible': [('picking_type_code', '=', 'outgoing')]}"> <field name="check_product_lines"/> </page> - <page string="Barcode Product" name="barcode_product" attrs="{'invisible': [('picking_type_code', '!=', 'incoming')]}"> + <page string="Barcode Product" name="barcode_product" + attrs="{'invisible': [('picking_type_code', '!=', 'incoming')]}"> <field name="barcode_product_lines"/> </page> <page string="Check Koli" name="check_koli" attrs="{'invisible': [('location_dest_id', '!=', 60)]}"> <field name="check_koli_lines"/> </page> - <page string="Mapping Koli" name="konfirm_koli" attrs="{'invisible': [('picking_type_code', '!=', 'outgoing')]}"> + <page string="Mapping Koli" name="konfirm_koli" + attrs="{'invisible': [('picking_type_code', '!=', 'outgoing')]}"> <field name="konfirm_koli_lines"/> </page> - <page string="Konfirm Koli" name="scan_koli" attrs="{'invisible': [('picking_type_code', '!=', 'outgoing')]}"> + <page string="Konfirm Koli" name="scan_koli" + attrs="{'invisible': [('picking_type_code', '!=', 'outgoing')]}"> <field name="scan_koli_lines"/> </page> </page> - + </field> </record> @@ -287,18 +312,20 @@ <field name="arch" type="xml"> <tree editable="bottom"> <field name="code_koli"/> - <field name="koli_id" options="{'no_create': True}" domain="[('state', '=', 'not_delivered')]"/> + <field name="koli_id" options="{'no_create': True}" domain="[('state', '=', 'not_delivered')]"/> <field name="scan_koli_progress"/> </tree> </field> </record> + <record id="konfirm_koli_tree" model="ir.ui.view"> <field name="name">konfirm.koli.tree</field> <field name="model">konfirm.koli</field> <field name="arch" type="xml"> <tree editable="bottom"> - <field name="pick_id" options="{'no_create': True}" required="1" domain="[('picking_type_code', '=', 'internal'), ('group_id', '=', parent.group_id), ('linked_manual_bu_out', '=', parent.id)]"/> + <field name="pick_id" options="{'no_create': True}" required="1" + domain="[('picking_type_code', '=', 'internal'), ('group_id', '=', parent.group_id), ('linked_manual_bu_out', '=', parent.id)]"/> </tree> </field> </record> @@ -307,7 +334,7 @@ <field name="name">check.koli.tree</field> <field name="model">check.koli</field> <field name="arch" type="xml"> - <tree editable="bottom"> + <tree editable="bottom"> <field name="koli"/> <field name="reserved_id"/> <field name="check_koli_progress"/> @@ -344,12 +371,14 @@ <field name="model">stock.move.line</field> <field name="inherit_id" ref="stock.view_stock_move_line_detailed_operation_tree"/> <field name="arch" type="xml"> - <tree editable="bottom" decoration-muted="(state == 'done' and is_locked == True)" decoration-danger="qty_done>product_uom_qty and state!='done' and parent.picking_type_code != 'incoming'" decoration-success="qty_done==product_uom_qty and state!='done' and not result_package_id"> + <tree editable="bottom" decoration-muted="(state == 'done' and is_locked == True)" + decoration-danger="qty_done>product_uom_qty and state!='done' and parent.picking_type_code != 'incoming'" + decoration-success="qty_done==product_uom_qty and state!='done' and not result_package_id"> <field name="note" placeholder="Add a note here"/> </tree> </field> </record> - + <record id="view_picking_internal_search_inherit" model="ir.ui.view"> <field name="name">stock.picking.internal.search.inherit</field> @@ -382,7 +411,7 @@ </form> </field> </record> - + <record id="action_warning_modal_wizard" model="ir.actions.act_window"> <field name="name">Peringatan Koli</field> <field name="res_model">warning.modal.wizard</field> |
