diff options
| author | Mqdd <ahmadmiqdad27@gmail.com> | 2026-02-04 14:38:58 +0700 |
|---|---|---|
| committer | Mqdd <ahmadmiqdad27@gmail.com> | 2026-02-04 14:38:58 +0700 |
| commit | d2a64b4e6023f0768d5c326c833fd5a9d8a11444 (patch) | |
| tree | 98149f6da42a924b7ad1a1b01c50feeaa138a0bb | |
| parent | 8bb3696e35dc122ea153566834a48ec0659e0101 (diff) | |
| parent | fb9b47c3fb5773782f84628764a01c5deb9be035 (diff) | |
Merge branch 'odoo-backup' of bitbucket.org:altafixco/indoteknik-addons into cr_renca_find
merge
33 files changed, 481 insertions, 116 deletions
diff --git a/indoteknik_api/controllers/api_v1/category.py b/indoteknik_api/controllers/api_v1/category.py index 7d66ad01..4514c2a0 100644 --- a/indoteknik_api/controllers/api_v1/category.py +++ b/indoteknik_api/controllers/api_v1/category.py @@ -250,4 +250,17 @@ class Category(controller.Controller): category = category.parent_frontend_id categories.reverse() - return self.response(categories, headers=[('Cache-Control', 'max-age=3600, public')])
\ No newline at end of file + return self.response(categories, headers=[('Cache-Control', 'max-age=3600, public')]) + + @http.route(prefix + 'category/<int:id>/short-desc', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_category_short_desc(self, id, **kw): + category = request.env['product.public.category'].browse(id) + + if not category.exists(): + return self.response(code=400, description='Category not found') + + return self.response({ + "id": category.id, + "short_desc": category.short_desc or "" + }, headers=[('Cache-Control', 'max-age=600, public')]) diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index 37808f94..e1360cfa 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -49,7 +49,7 @@ class AccountMove(models.Model): states={'draft': [('readonly', False)], 'sent': [('readonly', False)], 'sale': [('readonly', False)]}, domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", help="Dipakai untuk alamat tempel") - + address_invoice = fields.Char(related='real_invoice_id.street', string='Invoice Address', readonly=True) bills_efaktur_exporter = fields.Many2one('res.users', string='Efaktur Exporter') bills_date_efaktur = fields.Datetime(string="eFaktur Exported Date", required=False) @@ -176,7 +176,7 @@ class AccountMove(models.Model): lambda p: move.id in p.reconciled_invoice_ids.ids ) - if payment: + if payment: move.payment_date = payment[0].date elif move.reklas_misc_id: move.payment_date = move.reklas_misc_id.date @@ -185,7 +185,7 @@ class AccountMove(models.Model): def action_sync_promise_date(self): self.ensure_one() - finance_user_ids = [688] + finance_user_ids = [688] is_it = self.env.user.has_group('indoteknik_custom.group_role_it') if self.env.user.id not in finance_user_ids and not is_it: raise UserError('Hanya Finance (Widya) yang dapat menggunakan fitur ini.') @@ -286,7 +286,7 @@ class AccountMove(models.Model): if all(inv.reminder_sent_date == today for inv in invs): _logger.info(f"Reminder untuk {partner.name} sudah terkirim hari ini, skip.") continue - + promise_dates = [inv.customer_promise_date for inv in invs if inv.customer_promise_date] if promise_dates: earliest_promise = min(promise_dates) # ambil janji paling awal @@ -300,11 +300,11 @@ class AccountMove(models.Model): # skip semua jika partner centang dont_send_reminder_inv_all if partner.dont_send_reminder_inv_all: _logger.info(f"Partner {partner.name} skip karena dont_send_reminder_inv_all aktif") - continue + continue # cek parent hanya dengan flag dont_sent_reminder_inv_parent if not partner.dont_send_reminder_inv_parent and partner.email: emails.append(partner.email) - + # Ambil child contact yang di-checklist reminder_invoices reminder_contacts = self.env['res.partner'].search([ ('parent_id', '=', partner.id), @@ -312,7 +312,7 @@ class AccountMove(models.Model): ('email', '!=', False), ]) _logger.info(f"Email Reminder Child {reminder_contacts}") - + emails += reminder_contacts.mapped('email') if reminder_contacts: _logger.info(f"Email Reminder Child {reminder_contacts}") @@ -381,7 +381,7 @@ class AccountMove(models.Model): # tempo_link = 'http://localhost:2100/my/tempo' # payment_term = partner.previous_payment_term_id if partner.is_cbd_locked else partner.property_payment_term_id payment_term = invs[0].invoice_payment_term_id - + limit_info_html = f""" <p><b>Informasi Tambahan:</b></p> <ul style="font-size:12px; color:#333; line-height:1.4; margin:0; padding-left:0; list-style-position:inside;"> @@ -391,11 +391,11 @@ class AccountMove(models.Model): Sisa Kredit Limit: {formatLang(self.env, blocking_limit - outstanding_amount, currency_obj=currency)} </li> <li style="color:red;"> - Kredit Limit Terpakai: {formatLang(self.env, outstanding_amount, currency_obj=currency)} + Kredit Limit Terpakai: {formatLang(self.env, outstanding_amount, currency_obj=currency)} <span style="font-size:12px; color:#666;">({len(outstanding_invoices)} Transaksi)</span> </li> <li style="color:red;"> - Jatuh Tempo: {formatLang(self.env, overdue_amount, currency_obj=currency)} + Jatuh Tempo: {formatLang(self.env, overdue_amount, currency_obj=currency)} <span style="font-size:12px; color:#666;">({len(overdue_invoices)} Invoice)</span> </li> </ul> @@ -472,7 +472,7 @@ class AccountMove(models.Model): values = { 'subject': f"Reminder Invoice Due - {partner.name}", # 'email_to': 'andrifebriyadiputra@gmail.com', - 'email_to': email_to, + 'email_to': email_to, 'email_from': 'finance@indoteknik.co.id', 'email_cc': ",".join(sorted(set(cc_list))), 'body_html': body_html, @@ -528,7 +528,7 @@ class AccountMove(models.Model): # payment_term = rec.invoice_payment_term_id.line_ids[0].days # terima_faktur = rec.date_terima_tukar_faktur # payment = self.search([('ref', '=', rec.name), ('move_type', '=', 'entry')], limit=1) - + # if payment and terima_faktur: # date_diff = terima_faktur - payment.date # rec.length_of_payment = date_diff.days + payment_term @@ -589,7 +589,7 @@ class AccountMove(models.Model): template = self.env.ref('indoteknik_custom.mail_template_efaktur_document') for record in records: - if record.invoice_payment_term_id.id == 26: + if record.invoice_payment_term_id.id == 26: attachment = self.generate_attachment(record) email_values = { 'attachment_ids': [(4, attachment.id)] @@ -605,7 +605,7 @@ class AccountMove(models.Model): @api.model def create(self, vals): - vals['nomor_kwitansi'] = self.env['ir.sequence'].next_by_code('nomor.kwitansi') or '0' + vals['nomor_kwitansi'] = self.env['ir.sequence'].next_by_code('nomor.kwitansi') or '0' result = super(AccountMove, self).create(vals) # Tambahan: jika ini Vendor Bill dan tanggal belum diisi @@ -640,13 +640,13 @@ class AccountMove(models.Model): record.flag_delivery_amt = True else: record.flag_delivery_amt = False - + def compute_delivery_amt_text(self): tb = Terbilang() for record in self: res = '' - + try: if record.sale_id.delivery_amt > 0: tb.parse(int(record.sale_id.delivery_amt)) @@ -654,7 +654,7 @@ class AccountMove(models.Model): record.delivery_amt_text = res + ' Rupiah' except: record.delivery_amt_text = res - + @api.constrains('bills_efaktur_document') def _constrains_efaktur_document(self): @@ -722,13 +722,35 @@ class AccountMove(models.Model): raise UserError('Data Hanya Bisa Di Cancel') return res + def copy(self, default=None): + default = dict(default or {}) + + today = fields.Date.context_today(self) + + if self.invoice_date_due: + default.update({ + 'invoice_date_due': today, + }) + + move = super().copy(default) + + for line in move.line_ids: + if ( + line.account_id.user_type_id.type in ('receivable', 'payable') + and line.date_maturity + ): + line.date_maturity = today + + return move + + def button_cancel(self): res = super(AccountMove, self).button_cancel() if self.move_type == 'entry': po = self.env['purchase.order'].search([ ('move_id', 'in', [self.id]) ]) - + for order in po: if order: order.is_create_uangmuka = False @@ -741,7 +763,7 @@ class AccountMove(models.Model): res = super(AccountMove, self).button_draft() if not self.env.user.is_accounting: raise UserError('Hanya Accounting yang bisa Reset to Draft') - + for rec in self.line_ids: if rec.write_date != rec.create_date: if rec.statement_line_id and not rec.statement_line_id.statement_id.is_edit and rec.statement_line_id.statement_id.state == 'confirm': @@ -751,7 +773,7 @@ class AccountMove(models.Model): def action_post(self): if self._name != 'account.move': return super(AccountMove, self).action_post() - + # validation cant qty invoice greater than qty order if self.move_type == 'out_invoice': query = ["&",("name","=",self.invoice_origin),"|",("state","=","sale"),("state","=","done")] @@ -777,7 +799,7 @@ class AccountMove(models.Model): # raise UserError('Hanya Accounting yang bisa Posting') # if self._name == 'account.move': # for entry in self: - # entry.date_completed = datetime.utcnow() + # entry.date_completed = datetime.utcnow() # for line in entry.line_ids: # line.date_maturity = entry.date @@ -787,7 +809,7 @@ class AccountMove(models.Model): if not self.env.user.is_accounting: raise UserError("Hanya Finence yang bisa ubah data") return res - + def _compute_invoice_day_to_due(self): for invoice in self: invoice_day_to_due = 0 @@ -801,7 +823,7 @@ class AccountMove(models.Model): new_invoice_day_to_due = new_invoice_day_to_due.days invoice.invoice_day_to_due = invoice_day_to_due invoice.new_invoice_day_to_due = new_invoice_day_to_due - + def _compute_bill_day_to_due(self): for rec in self: rec.bill_day_to_due = rec.payment_schedule or rec.invoice_date_due @@ -831,21 +853,21 @@ class AccountMove(models.Model): add_days += line.days due_date = tukar_date + timedelta(days=add_days) invoice.invoice_date_due = due_date - + def open_form_multi_update(self): action = self.env['ir.actions.act_window']._for_xml_id('indoteknik_custom.action_account_move_multi_update') action['context'] = { 'move_ids': [x.id for x in self] } return action - + def open_form_multi_update_bills(self): action = self.env['ir.actions.act_window']._for_xml_id('indoteknik_custom.action_account_move_multi_update_bills') action['context'] = { 'move_ids': [x.id for x in self] } return action - + @api.constrains('efaktur_id', 'ref', 'date', 'journal_id', 'name') def constrains_edit(self): for rec in self.line_ids: @@ -859,10 +881,10 @@ class AccountMove(models.Model): # if rec.statement_line_id and not rec.statement_line_id.statement_id.is_edit and rec.statement_line_id.statement_id.state == 'confirm': # raise UserError('Bank Statement di Lock, Minta admin reconcile untuk unlock') # return res - + def validate_faktur_for_export(self): - invoices = self.filtered(lambda inv: not inv.is_efaktur_exported and - inv.state == 'posted' and + invoices = self.filtered(lambda inv: not inv.is_efaktur_exported and + inv.state == 'posted' and inv.move_type == 'out_invoice') invalid_invoices = self - invoices @@ -874,10 +896,10 @@ class AccountMove(models.Model): )) return invoices - + def export_faktur_to_xml(self): valid_invoices = self - + coretax_faktur = self.env['coretax.faktur'].create({}) response = coretax_faktur.export_to_download( diff --git a/indoteknik_custom/models/advance_payment_request.py b/indoteknik_custom/models/advance_payment_request.py index f973a9da..8cadb1b6 100644 --- a/indoteknik_custom/models/advance_payment_request.py +++ b/indoteknik_custom/models/advance_payment_request.py @@ -55,12 +55,14 @@ class AdvancePaymentRequest(models.Model): ('pengajuan2', 'Menunggu Approval AP'), ('pengajuan3', 'Menunggu Approval Pimpinan'), ('approved', 'Approved'), + ('cancel','Cancel') ], string='Status', default='draft', tracking=3, index=True, track_visibility='onchange') status_pay_down_payment = fields.Selection([ ('pending', 'Pending'), ('payment', 'Payment'), + ('cancel','Cancel') ], string='Status Pembayaran', default='pending', tracking=3) name_approval_departement = fields.Char(string='Approval Departement') @@ -639,10 +641,16 @@ class AdvancePaymentRequest(models.Model): today = date.today() for rec in self: - current_days = rec.days_remaining or 0 - current_due_date = rec.estimated_return_date or False - if rec.type_request == 'pum': - is_settlement_approved = any(s.status == 'approved' for s in rec.settlement_ids) + # current_days = rec.days_remaining or 0 + # current_due_date = rec.estimated_return_date or False + current_days = 0 + current_due_date = False + + is_settlement_approved = any(s.status == 'approved' for s in rec.settlement_ids) + is_pum_canceled = (rec.status == 'cancel') + + if rec.type_request == 'pum' and not is_pum_canceled and not is_settlement_approved: + if not is_settlement_approved: due_date = False @@ -816,6 +824,52 @@ class AdvancePaymentRequest(models.Model): rec._compute_grand_total_reimburse() rec.nominal = rec.grand_total_reimburse return rec + + def action_open_cancel_wizard(self): + """Membuka Wizard Pop-up untuk Cancel PUM/Reimburse""" + self.ensure_one() + + if self.move_id: + raise UserError(_("Pengajuan tidak dapat dibatalkan karena Journal sudah terbentuk.")) + + if self.settlement_ids and any(s.status != 'draft' for s in self.settlement_ids): + raise UserError(_("Pengajuan tidak dapat dibatalkan karena sudah ada proses realisasi.")) + + return { + 'name': _('Alasan Pembatalan'), + 'type': 'ir.actions.act_window', + 'res_model': 'advance.payment.cancel.wizard', + 'view_mode': 'form', + 'target': 'new', + 'context': { + 'default_request_id': self.id, + } + } + +class AdvancePaymentCancelWizard(models.TransientModel): + _name = 'advance.payment.cancel.wizard' + _description = 'Wizard untuk Membatalkan PUM/Reimburse' + + request_id = fields.Many2one('advance.payment.request', string='Dokumen', readonly=True) + reason = fields.Text(string='Alasan Pembatalan', required=True) + + def action_confirm_cancel(self): + self.ensure_one() + request = self.request_id + if request.move_id: + raise UserError("Tidak bisa melakukan cancel karena Jurnal (Move ID) sudah terbentuk.") + + request.write({'status': 'cancel'}) + request.write({'status_pay_down_payment': 'cancel'}) + + request.message_post( + body=f"Pengajuan telah <b>DIBATALKAN</b> oleh {self.env.user.name}.<br/>" + f"<b>Alasan:</b> {self.reason}", + message_type="comment", + subtype_xmlid="mail.mt_note", + ) + + return {'type': 'ir.actions.act_window_close'} class AdvancePaymentUsageLine(models.Model): diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py index 4b0ce325..0b2f7d1b 100644 --- a/indoteknik_custom/models/automatic_purchase.py +++ b/indoteknik_custom/models/automatic_purchase.py @@ -499,7 +499,8 @@ class AutomaticPurchase(models.Model): # _logger.info('test %s' % point.product_id.name) if point.product_id.qty_available_bandengan > point.product_min_qty: continue - qty_purchase = point.product_max_qty - point.product_id.qty_incoming_bandengan - point.product_id.qty_available_bandengan + # qty_purchase = point.product_max_qty - point.product_id.qty_incoming_bandengan - point.product_id.qty_available_bandengan + qty_purchase = point.product_max_qty - point.product_id.qty_available_bandengan po_line = self.env['purchase.order.line'].search([('product_id', '=', point.product_id.id), ('order_id.state', '=', 'done')], order='id desc', limit=1) if self.vendor_id: diff --git a/indoteknik_custom/models/commision.py b/indoteknik_custom/models/commision.py index 441dd54f..983c07fe 100644 --- a/indoteknik_custom/models/commision.py +++ b/indoteknik_custom/models/commision.py @@ -489,7 +489,10 @@ class CustomerCommision(models.Model): raise UserError('Line sudah ada, tidak bisa di generate ulang') if self.commision_type == 'fee': - self._generate_customer_commision_fee() + if self.brand_ids: + self._generate_customer_commision_rebate() + else: + self._generate_customer_commision_fee() else: self._generate_customer_commision_rebate() diff --git a/indoteknik_custom/models/price_group.py b/indoteknik_custom/models/price_group.py index 1b1c817f..fce78fff 100644 --- a/indoteknik_custom/models/price_group.py +++ b/indoteknik_custom/models/price_group.py @@ -18,6 +18,8 @@ class PriceGroup(models.Model): group6 = fields.Float(string='Kelompok 6 (%)') group7 = fields.Float(string='Kelompok 7 (%)') group8 = fields.Float(string='Kelompok 8 (%)') + group9 = fields.Float(string='Kelompok 9 (%)') + group10 = fields.Float(string='Kelompok 10 (%)') def collect_price_group(self): PRICE_GROUP_ID = { @@ -47,4 +49,6 @@ class Manufacture(models.Model): ('group6', 'Kelompok 6'), ('group7', 'Kelompok 7'), ('group8', 'Kelompok 8'), + ('group9', 'Kelompok 9'), + ('group10', 'Kelompok 10'), ], string='Pricing Group', copy=False) diff --git a/indoteknik_custom/models/product_public_category.py b/indoteknik_custom/models/product_public_category.py index 1039ec52..dadcb181 100755 --- a/indoteknik_custom/models/product_public_category.py +++ b/indoteknik_custom/models/product_public_category.py @@ -15,6 +15,7 @@ class ProductPublicCategory(models.Model): child_frontend_id = fields.One2many('product.public.category', 'parent_frontend_id', string='Children Frontend Categories') child_frontend_id2 = fields.Many2many('product.public.category', relation='website_categories_child_frontend_rel', column1='website_categories_homepage_id', column2='product_public_category_id', string='Category Level 3') sequence_frontend = fields.Integer(help="Gives the sequence order when displaying a list of product categories.", index=True) + short_desc = fields.Char(string='Short Description') # @api.model # def _onchange_child_frontend_id2(self, parent): diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py index 75adb352..397bd06d 100755 --- a/indoteknik_custom/models/product_template.py +++ b/indoteknik_custom/models/product_template.py @@ -18,13 +18,13 @@ class ProductTemplate(models.Model): x_attribute_set_id = fields.Integer( string="Magento Attribute Set ID", - default=0, - index=True, - help="Attribute Set ID dari Magento" + help="Attribute Set ID dari Magento", + readonly=True ) x_attribute_set_name = fields.Char( string="Magento Attribute Set Name", - help="Attribute Set Name dari Magento" + help="Attribute Set Name dari Magento", + readonly=True ) image_carousel_lines = fields.One2many( @@ -85,7 +85,6 @@ class ProductTemplate(models.Model): merchandise_ok = fields.Boolean(string='Product Promotion') print_barcode = fields.Boolean(string='Print Barcode', default=True) # qr_code = fields.Binary("QR Code", compute='_compute_qr_code') - # has_magento = fields.Boolean(string='Has Magento?', default=False) @api.model def create(self, vals): @@ -967,6 +966,8 @@ class ProductProduct(models.Model): return True + has_magento = fields.Boolean(string='Has Magento?', default=False, readonly=True) + def generate_product_sla(self): product_variant_ids = self.env.context.get('active_ids', []) product_variant = self.search([('id', 'in', product_variant_ids)]) diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py index 3d22b0f0..6c3e4185 100755 --- a/indoteknik_custom/models/purchase_order.py +++ b/indoteknik_custom/models/purchase_order.py @@ -53,6 +53,7 @@ class PurchaseOrder(models.Model): total_so_percent_margin = fields.Float( 'SO Margin%', compute='compute_total_margin', help="Total % Margin in Sales Order Header") + amount_cashback = fields.Float('Cashback', compute = 'compute_total_margin', help = 'Total Cashback brand Altama') amount_total_without_service = fields.Float('AmtTotalWithoutService', compute='compute_amt_total_without_service') summary_qty_po = fields.Float('Total Qty', compute='_compute_summary_qty') summary_qty_receipt = fields.Float('Summary Qty Receipt', compute='_compute_summary_qty') @@ -1079,20 +1080,13 @@ class PurchaseOrder(models.Model): ) % order.name) def button_confirm(self): - if self.env.user.id != 7 and not self.env.user.is_leader: # Pimpinan - if '/PJ/' in self.name: - low_margin_lines = self.order_sales_match_line.filtered( - lambda match: match.so_header_margin <= 15.0 - ) - price_change_detected = any(line.price_unit_before for line in self.order_line) - if low_margin_lines and price_change_detected: - # raise UserError("Matches SO terdapat item dengan header margin SO <= 15%. Approval Pimpinan diperlukan.") - raise UserError("Approval Pimpinan diperlukan jika terdapat perubahan Unit Price pada PO Line yang Matches SO item memiliki header margin SO <= 15%") - # else: - # is_po_manual = '/A/' not in self.name and '/MO/' not in self.name - # if is_po_manual: - # if not self.order_sales_match_line: - # raise UserError("Tidak ada matches SO, Approval Pimpinan diperlukan.") + # if self.env.user.id != 7 and not self.env.user.is_leader: # Pimpinan + # if '/PJ/' in self.name: + # price_change_detected = any(line.price_unit_before for line in self.order_line) + # if price_change_detected: + # if self.order_sales_match_line: + # if self.total_percent_margin <= 15.0: + # raise UserError("Approval Pimpinan diperlukan jika terdapat perubahan Unit Price pada PO Line dan Memiliki Margin <= 15%") self._check_assets_note() # self._check_payment_term() # check payment term @@ -1417,19 +1411,36 @@ class PurchaseOrder(models.Model): real_item_margin = sales_price - purchase_price sum_margin += real_item_margin + cashback_amount = 0 + if self.partner_id.id == 5571: + cashback_percent = line.product_id.x_manufacture.cashback_percent or 0.0 + if cashback_percent > 0: + cashback_amount = purchase_price * cashback_percent + purchase_price -= cashback_amount + + # line.amount_cashback = cashback_amount + if sum_so_margin != 0 and sum_sales_price != 0 and sum_margin != 0: self.total_so_margin = sum_so_margin self.total_so_percent_margin = round((sum_so_margin / sum_sales_price), 2) * 100 self.total_margin = sum_margin self.total_percent_margin = round((sum_margin / sum_sales_price), 2) * 100 + self.amount_cashback = 0 + elif self.partner_id.id == 5571 and sum_so_margin != 0 and sum_sales_price != 0 and sum_margin != 0 and cashback_amount != 0: + self.total_so_margin = sum_so_margin + self.total_so_percent_margin = round((sum_so_margin / sum_sales_price), 2) * 100 + self.total_margin = sum_margin + self.total_percent_margin = round((sum_margin / sum_sales_price), 2) * 100 + self.amount_cashback = cashback_amount else: self.total_margin = 0 self.total_percent_margin = 0 self.total_so_margin = 0 self.total_so_percent_margin = 0 + self.amount_cashback = 0 def compute_total_margin_from_apo(self): - sum_so_margin = sum_sales_price = sum_margin = 0 + sum_so_margin = sum_sales_price = sum_margin = cashback_amount = 0 for line in self.order_sales_match_line: po_line = self.env['purchase.order.line'].search([ ('product_id', '=', line.product_id.id), @@ -1466,18 +1477,27 @@ class PurchaseOrder(models.Model): if line.purchase_order_id.delivery_amt > 0: purchase_price += line.purchase_order_id.delivery_amt + if self.partner_id.id == 5571: + cashback_percent = line.product_id.x_manufacture.cashback_percent or 0.0 + if cashback_percent > 0: + cashback_amount = purchase_price * cashback_percent + purchase_price -= cashback_amount + real_item_margin = sales_price - purchase_price sum_margin += real_item_margin + self.amount_cashback = cashback_amount # Akumulasi hasil akhir if sum_sales_price != 0: self.total_so_margin = sum_so_margin self.total_so_percent_margin = round((sum_so_margin / sum_sales_price), 2) * 100 self.total_margin = sum_margin self.total_percent_margin = round((sum_margin / sum_sales_price), 2) * 100 + self.amount_cashback = cashback_amount else: self.total_margin = self.total_percent_margin = 0 self.total_so_margin = self.total_so_percent_margin = 0 + self.amount_cashback = 0 def compute_amt_total_without_service(self): diff --git a/indoteknik_custom/models/purchase_order_line.py b/indoteknik_custom/models/purchase_order_line.py index 8c72887d..76dcc09e 100755 --- a/indoteknik_custom/models/purchase_order_line.py +++ b/indoteknik_custom/models/purchase_order_line.py @@ -23,6 +23,9 @@ class PurchaseOrderLine(models.Model): so_item_percent_margin = fields.Float( 'SO Margin%', compute='compute_item_margin', help="Total % Margin in Sales Order Header") + amount_cashback = fields.Float( + 'SO Margin%', compute='_compute_cashback_brand', + help="Total % Margin in Sales Order Header") delivery_amt_line = fields.Float('DeliveryAmtLine', compute='compute_delivery_amt_line') line_no = fields.Integer('No', default=0) qty_available = fields.Float('Qty Available', compute='_compute_qty_stock') @@ -373,6 +376,9 @@ class PurchaseOrderLine(models.Model): purchase_price = line.price_subtotal if order.delivery_amount > 0: purchase_price += line.delivery_amt_line + + if line.amount_cashback > 0: + purchase_price = purchase_price - line.amount_cashback # Hitung margin dan persentase margin real_item_margin = total_sales_price - purchase_price @@ -384,6 +390,46 @@ class PurchaseOrderLine(models.Model): sum_margin += real_item_margin + def _compute_cashback_brand(self): + start_date = datetime(2026, 2, 1, 0, 0, 0) + + for line in self: + line.amount_cashback = 0.0 + + product = line.product_id + order = line.order_id + + if not product or not order: + continue + + if order.partner_id.id != 5571: + continue + + sales_matches = self.env['purchase.order.sales.match'].search([ + ('purchase_order_id', '=', order.id), + ('product_id', '=', product.id) + ]) + + total_cashback = 0.0 + + for match in sales_matches: + so_line = match.sale_line_id + so_order = so_line.order_id + + if not so_order.date_order or so_order.date_order < start_date: + continue + + cashback_percent = product.x_manufacture.cashback_percent or 0.0 + if cashback_percent <= 0: + continue + sales_price = so_line.price_reduce_taxexcl * match.qty_so + + cashback = sales_price * cashback_percent + total_cashback += cashback + + line.amount_cashback = total_cashback + + def compute_delivery_amt_line(self): for line in self: if line.product_id.type == 'product': diff --git a/indoteknik_custom/models/purchasing_job.py b/indoteknik_custom/models/purchasing_job.py index 7a7e70b4..e457b86c 100644 --- a/indoteknik_custom/models/purchasing_job.py +++ b/indoteknik_custom/models/purchasing_job.py @@ -24,7 +24,8 @@ class PurchasingJob(models.Model): ('apo', 'APO') ], string='APO?') purchase_representative_id = fields.Many2one('res.users', string="Purchase Representative", readonly=True) - note = fields.Char(string="Note Detail") + note = fields.Char(string="Note") + note_detail = fields.Text(string="Note Detail") date_po = fields.Datetime(string='Date PO', copy=False) so_number = fields.Text(string='SO Number', copy=False) check_pj = fields.Boolean(compute='_get_check_pj', string='Linked') @@ -126,6 +127,7 @@ class PurchasingJob(models.Model): pmp.action, max(pjs.status_apo::text) AS status_apo, max(pjs.note::text) AS note, + max(pjs.note_detail::text) AS note_detail, max(pjs.date_po::text) AS date_po, pmp.so_number, CASE diff --git a/indoteknik_custom/models/purchasing_job_multi_update.py b/indoteknik_custom/models/purchasing_job_multi_update.py index 80a43e45..0eca499f 100644 --- a/indoteknik_custom/models/purchasing_job_multi_update.py +++ b/indoteknik_custom/models/purchasing_job_multi_update.py @@ -20,10 +20,19 @@ class PurchasingJobMultiUpdate(models.TransientModel): # purchasing_job_state.unlink() - purchasing_job_state.create({ - 'purchasing_job_id': product.id, - 'status_apo': 'apo', - }) + vals = { + 'purchasing_job_id': product.id, # Pastikan ID ini benar mapping ke ID produk + 'status_apo': 'apo', + } + + if purchasing_job_state: + purchasing_job_state.write(vals) + else: + purchasing_job_state.create(vals) + # purchasing_job_state.create({ + # 'purchasing_job_id': product.id, + # 'status_apo': 'apo', + # }) apo = self.env['automatic.purchase'].generate_regular_purchase(products) return { diff --git a/indoteknik_custom/models/purchasing_job_state.py b/indoteknik_custom/models/purchasing_job_state.py index d014edfe..ca557de1 100644 --- a/indoteknik_custom/models/purchasing_job_state.py +++ b/indoteknik_custom/models/purchasing_job_state.py @@ -14,5 +14,6 @@ class PurchasingJobState(models.Model): ('not_apo', 'Belum APO'), ('apo', 'APO') ], string='APO?', copy=False) - note = fields.Char(string="Note Detail", copy=False) + note = fields.Char(string="Note", copy=False) + note_detail = fields.Text(string="Note Detail", copy=False) date_po = fields.Datetime(string='Date PO', copy=False) diff --git a/indoteknik_custom/models/refund_sale_order.py b/indoteknik_custom/models/refund_sale_order.py index c22e84ab..4c3ca52e 100644 --- a/indoteknik_custom/models/refund_sale_order.py +++ b/indoteknik_custom/models/refund_sale_order.py @@ -62,7 +62,8 @@ class RefundSaleOrder(models.Model): ('uang', 'Refund Lebih Bayar'), ('retur_half', 'Refund Retur Sebagian'), ('retur', 'Refund Retur Full'), - ('salah_transfer', 'Salah Transfer') + ('salah_transfer', 'Salah Transfer'), + ('berita_acara', 'Kebutuhan Berita Acara') ], string='Refund Type', required=True) tukar_guling_ids = fields.One2many( @@ -242,7 +243,7 @@ class RefundSaleOrder(models.Model): ) invoices = sale_orders.mapped('invoice_ids').filtered( - lambda inv: inv.move_type in ['out_invoice', 'out_refund'] and inv.state != 'cancel' + lambda inv: inv.move_type in ['out_invoice', 'out_refund'] and inv.state == 'posted' ) if invoices: vals['invoice_ids'] = [(6, 0, invoices.ids)] @@ -251,7 +252,7 @@ class RefundSaleOrder(models.Model): invoice_ids_data = vals.get('invoice_ids', []) invoice_ids = invoice_ids_data[0][2] if invoice_ids_data and invoice_ids_data[0][0] == 6 else [] invoices = self.env['account.move'].browse(invoice_ids) - if invoice_ids and refund_type and refund_type not in ['uang', 'barang_kosong_sebagian', 'barang_kosong', 'retur_half']: + if invoice_ids and refund_type and refund_type not in ['uang', 'barang_kosong_sebagian', 'barang_kosong', 'retur_half', 'berita_acara']: raise UserError("Refund type Hanya Bisa Lebih Bayar, Barang Kosong Sebagian, atau Retur jika ada invoice") if not invoice_ids and refund_type and refund_type in ['uang', 'barang_kosong_sebagian', 'retur_half']: @@ -296,6 +297,7 @@ class RefundSaleOrder(models.Model): ]) piutangbca = self.env['account.move'] piutangmdr = self.env['account.move'] + cabinvoice = self.env['account.move'] for inv_name in invoices.mapped('name'): piutangbca |= self.env['account.move'].search([ @@ -308,6 +310,11 @@ class RefundSaleOrder(models.Model): ('journal_id', '=', 7), ('state', '=', 'posted'), ]) + cabinvoice |= self.env['account.move'].search([ + ('ref', 'ilike', inv_name), + ('journal_id', '=', 11), + ('state', '=', 'posted'), + ]) misc = self.env['account.move'] if invoices: @@ -378,6 +385,7 @@ class RefundSaleOrder(models.Model): has_moves3 = bool(moves3) has_piutangmdr = bool(piutangmdr) has_piutangbca = bool(piutangbca) + has_cabinvoice = bool(cabinvoice) has_misc = bool(misc) has_ongkir = bool(moves_ongkir) ssos = self.env['sale.order'].browse(so_ids) @@ -385,7 +393,7 @@ class RefundSaleOrder(models.Model): sisa_uang_masuk = 0.0 - has_journal = has_moves or has_moves2 or has_moves3 or has_piutangbca or has_piutangmdr or has_misc + has_journal = has_moves or has_moves2 or has_moves3 or has_piutangbca or has_piutangmdr or has_misc or has_cabinvoice if has_moves: sisa_uang_masuk += sum(moves.mapped('amount_total_signed')) @@ -397,6 +405,8 @@ class RefundSaleOrder(models.Model): sisa_uang_masuk += sum(moves3.mapped('amount_total_signed')) if has_piutangbca: sisa_uang_masuk += sum(piutangbca.mapped('amount_total_signed')) + if has_cabinvoice: + sisa_uang_masuk += sum(cabinvoice.mapped('amount_total_signed')) if has_piutangmdr: sisa_uang_masuk += sum(piutangmdr.mapped('amount_total_signed')) if has_misc: @@ -425,13 +435,17 @@ class RefundSaleOrder(models.Model): total_invoice = sum(self.env['account.move'].browse(invoice_ids).mapped('amount_total_signed')) if invoice_ids else 0.0 vals['total_invoice'] = total_invoice amount_refund = vals.get('amount_refund', 0.0) - can_refund = sisa_uang_masuk - total_invoice - - if amount_refund > can_refund or can_refund == 0.0: - raise ValidationError( - _("Maksimal refund yang bisa dilakukan adalah sebesar %s. " - "Silakan sesuaikan jumlah refund.") % (can_refund) - ) + can_refund = 0.0 + if refund_type == 'berita_acara': + can_refund = sisa_uang_masuk + else: + can_refund = sisa_uang_masuk - total_invoice + if refund_type != 'berita_acara': + if amount_refund > can_refund or can_refund == 0.0: + raise ValidationError( + _("Maksimal refund yang bisa dilakukan adalah sebesar %s. " + "Silakan sesuaikan jumlah refund.") % (can_refund) + ) if amount_refund <= 0.00: raise ValidationError('Total Refund harus lebih dari 0 jika ingin mengajukan refund') @@ -483,7 +497,7 @@ class RefundSaleOrder(models.Model): valid_invoices = sale_orders.mapped('invoice_ids').filtered( - lambda inv: inv.move_type in ['out_invoice', 'out_refund'] and inv.state != 'cancel' + lambda inv: inv.move_type in ['out_invoice', 'out_refund'] and inv.state == 'posted' ) vals['invoice_ids'] = [(6, 0, valid_invoices.ids)] vals['ongkir'] = sum(so.delivery_amt or 0.0 for so in sale_orders) @@ -526,7 +540,7 @@ class RefundSaleOrder(models.Model): else: invoice_ids = rec.invoice_ids.ids - if invoice_ids and vals.get('refund_type', rec.refund_type) not in ['uang', 'barang_kosong_sebagian', 'barang_kosong', 'retur_half', 'retur']: + if invoice_ids and vals.get('refund_type', rec.refund_type) not in ['uang', 'barang_kosong_sebagian', 'barang_kosong', 'retur_half', 'retur', 'berita_acara']: raise UserError("Refund type Hanya Bisa Lebih Bayar, Barang Kosong Sebagian, atau Retur jika ada invoice") if not invoice_ids and vals.get('refund_type', rec.refund_type) in ['uang', 'barang_kosong_sebagian', 'retur_half']: @@ -539,10 +553,28 @@ class RefundSaleOrder(models.Model): if any(field in vals for field in ['uang_masuk', 'invoice_ids', 'ongkir', 'sale_order_ids', 'amount_refund']): total_invoice = sum(self.env['account.move'].browse(invoice_ids).mapped('amount_total_signed')) vals['total_invoice'] = total_invoice - uang_masuk = rec.uang_masuk - can_refund = uang_masuk - total_invoice - + uang_masuk = vals.get('uang_masuk', rec.uang_masuk) amount_refund = vals.get('amount_refund', rec.amount_refund) + can_refund = 0.0 + total_refunded = 0.0 + + if refund_type == 'berita_acara': + can_refund = uang_masuk + remaining = uang_masuk - amount_refund + else: + can_refund = uang_masuk - total_invoice + + existing_refunds = self.search([ + ('sale_order_ids', 'in', so_ids), + ('id', '!=', rec.id) + ]) + total_refunded = sum(existing_refunds.mapped('amount_refund')) + + if existing_refunds: + remaining = uang_masuk - total_refunded + else: + remaining = uang_masuk - amount_refund + if amount_refund > can_refund: raise ValidationError( @@ -592,7 +624,7 @@ class RefundSaleOrder(models.Model): for rec in self: move_links = [] - invoice_ids = rec.sale_order_ids.mapped('invoice_ids') + invoice_ids = rec.sale_order_ids.mapped('invoice_ids').filtered(lambda m: m.state == 'posted') moves = self.env['account.move'].search([ ('sale_id', 'in', rec.sale_order_ids.ids), @@ -602,6 +634,7 @@ class RefundSaleOrder(models.Model): piutangbca = self.env['account.move'] piutangmdr = self.env['account.move'] + cabinvoice = self.env['account.move'] for inv_name in invoice_ids.mapped('name'): piutangbca |= self.env['account.move'].search([ @@ -614,6 +647,11 @@ class RefundSaleOrder(models.Model): ('journal_id', '=', 7), ('state', '=', 'posted'), ]) + cabinvoice |= self.env['account.move'].search([ + ('ref', 'ilike', inv_name), + ('journal_id', '=', 11), + ('state', '=', 'posted'), + ]) moves2 = self.env['account.move'] if rec.sale_order_ids: @@ -659,15 +697,13 @@ class RefundSaleOrder(models.Model): ('line_ids.account_id', '=', 450), ('line_ids.account_id', '=', 668), ] - - if so_names: domain += ['|'] * (len(so_names) - 1) for name in so_names: domain.append(('ref', 'ilike', name)) - moves_ongkir = self.env['account.move'].search(domain) + moves_ongkir = self.env['account.move'].search(domain) - all_moves = moves | piutangbca | piutangmdr | misc | moves2 | moves_ongkir + all_moves = moves | piutangbca | piutangmdr | misc | moves2 | moves_ongkir | cabinvoice for move in all_moves: url = f"/web#id={move.id}&model=account.move&view_type=form" @@ -695,7 +731,7 @@ class RefundSaleOrder(models.Model): for so in self.sale_order_ids: self.ongkir += so.delivery_amt or 0.0 valid_invoices = so.invoice_ids.filtered( - lambda inv: inv.move_type in ['out_invoice', 'out_refund'] and inv.state != 'cancel' + lambda inv: inv.move_type in ['out_invoice', 'out_refund'] and inv.state == 'posted' ) all_invoices |= valid_invoices total_invoice += sum(valid_invoices.mapped('amount_total_signed')) @@ -713,6 +749,7 @@ class RefundSaleOrder(models.Model): piutangbca = self.env['account.move'] piutangmdr = self.env['account.move'] + cabinvoice = self.env['account.move'] for inv_name in all_invoices.mapped('name'): piutangbca |= self.env['account.move'].search([ @@ -725,6 +762,11 @@ class RefundSaleOrder(models.Model): ('journal_id', '=', 7), ('state', '=', 'posted'), ]) + cabinvoice |= self.env['account.move'].search([ + ('ref', 'ilike', inv_name), + ('journal_id', '=', 11), + ('state', '=', 'posted'), + ]) misc = self.env['account.move'] if all_invoices: @@ -799,6 +841,7 @@ class RefundSaleOrder(models.Model): has_moves3 = bool(moves3) has_piutangmdr = bool(piutangmdr) has_piutangbca = bool(piutangbca) + has_cabinvoice = bool(cabinvoice) has_misc = bool(misc) has_ongkir = bool(moves_ongkir) ssos = self.env['sale.order'].browse(so_ids) @@ -812,6 +855,8 @@ class RefundSaleOrder(models.Model): sisa_uang_masuk += sum(moves.mapped('amount_total_signed')) if has_moves2: sisa_uang_masuk += sum(moves2.mapped('amount_total_signed')) + if has_cabinvoice: + sisa_uang_masuk += sum(cabinvoice.mapped('amount_total_signed')) if has_moves3: sisa_uang_masuk += sum(moves3.mapped('amount_total_signed')) if has_piutangbca: diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 17691798..a4bc2309 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -2305,7 +2305,7 @@ class SaleOrder(models.Model): search_bom = self.env['mrp.production'].search([('product_id', '=', line.product_id.id), ('sale_order', '=', order.id), ('state', '!=', 'cancel')], order='name desc') if search_bom: - confirmed_bom = search_bom.filtered(lambda x: x.state == 'confirmed' or x.state == 'done') + confirmed_bom = search_bom.filtered(lambda x: x.state in ['confirmed', 'to_close', 'progress', 'done']) if not confirmed_bom: raise UserError( "Product BOM belum dikonfirmasi di Manufacturing Orders. Silakan hubungi Purchasing.") @@ -3438,7 +3438,7 @@ class SaleOrder(models.Model): def button_refund(self): self.ensure_one() - invoice_ids = self.invoice_ids.filtered(lambda inv: inv.state != 'cancel') + invoice_ids = self.invoice_ids.filtered(lambda inv: inv.state == 'posted') moves = self.env['account.move'].search([ ('sale_id', '=', self.id), @@ -3447,6 +3447,7 @@ class SaleOrder(models.Model): ]) piutangbca = self.env['account.move'] piutangmdr = self.env['account.move'] + cabinvoice = self.env['account.move'] for inv_name in invoice_ids.mapped('name'): piutangbca |= self.env['account.move'].search([ @@ -3459,6 +3460,11 @@ class SaleOrder(models.Model): ('journal_id', '=', 7), ('state', '=', 'posted'), ]) + cabinvoice |= self.env['account.move'].search([ + ('ref', 'ilike', inv_name), + ('journal_id', '=', 11), + ('state', '=', 'posted'), + ]) moves2 = self.env['account.move'].search([ ('ref', 'ilike', self.name), @@ -3473,6 +3479,7 @@ class SaleOrder(models.Model): has_moves2 = bool(moves2) has_piutangmdr = bool(piutangmdr) has_piutangbca = bool(piutangbca) + has_cabinvoice = bool(cabinvoice) has_settlement = self.payment_status == 'settlement' if has_moves and has_settlement: @@ -3483,6 +3490,8 @@ class SaleOrder(models.Model): total_uang_muka = sum(moves2.mapped('amount_total_signed')) elif has_settlement: total_uang_muka = self.gross_amount + elif has_cabinvoice: + total_uang_muka = sum(cabinvoice.mapped('amount_total_signed')) elif has_piutangbca: total_uang_muka = sum(piutangbca.mapped('amount_total_signed')) elif has_piutangmdr: diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py index 1df1a058..dd44f84a 100644 --- a/indoteknik_custom/models/sale_order_line.py +++ b/indoteknik_custom/models/sale_order_line.py @@ -17,6 +17,7 @@ class SaleOrderLine(models.Model): help="Total % Margin in Sales Order Header") item_percent_margin_before = fields.Float('%Margin Before', compute='_compute_item_percent_margin_before', help="Total % Margin excluding third party in Sales Order Header") + amount_cashback = fields.Float('Cashback Brand', compute='_compute_cashback_brand', help='Cashback from product who has cashback percent in manufacture') initial_discount = fields.Float('Initial Discount') vendor_id = fields.Many2one( 'res.partner', string='Vendor', readonly=True, @@ -164,7 +165,10 @@ class SaleOrderLine(models.Model): purchase_price = line.purchase_price if line.purchase_tax_id.price_include: - purchase_price = line.purchase_price / 1.11 + purchase_price = line.purchase_price / (1 + (line.purchase_tax_id.amount / 100)) + + if line.amount_cashback > 0: + purchase_price = purchase_price - line.amount_cashback purchase_price = purchase_price * line.product_uom_qty margin_per_item = sales_price - purchase_price @@ -186,7 +190,10 @@ class SaleOrderLine(models.Model): purchase_price = line.purchase_price if line.purchase_tax_id and line.purchase_tax_id.price_include: - purchase_price = line.purchase_price / 1.11 + purchase_price = line.purchase_price / (1 + (line.purchase_tax_id.amount / 100)) + + if line.amount_cashback > 0: + purchase_price = purchase_price - line.amount_cashback purchase_price = purchase_price * line.product_uom_qty @@ -215,7 +222,10 @@ class SaleOrderLine(models.Model): purchase_price = line.purchase_price if line.purchase_tax_id.price_include: - purchase_price = line.purchase_price / 1.11 + purchase_price = line.purchase_price / (1 + (line.purchase_tax_id.amount / 100)) + + if line.amount_cashback > 0: + purchase_price = purchase_price - line.amount_cashback purchase_price = purchase_price * line.product_uom_qty margin_per_item = sales_price - purchase_price @@ -241,12 +251,47 @@ class SaleOrderLine(models.Model): purchase_price = line.purchase_price if line.purchase_tax_id.price_include: - purchase_price = line.purchase_price / 1.11 + purchase_price = line.purchase_price / (1 + (line.purchase_tax_id.amount / 100)) + + if line.amount_cashback > 0: + purchase_price = purchase_price - line.amount_cashback purchase_price = purchase_price * line.product_uom_qty margin_per_item = sales_price - purchase_price line.item_before_margin = margin_per_item + def _compute_cashback_brand(self): + start_date = datetime(2026, 2, 1, 0, 0, 0) + for line in self: + line.amount_cashback = 0 + + if not line.product_id: + continue + + if line.order_id.date_order < start_date: + continue + + price, taxes, vendor_id = self._get_purchase_price(line.product_id) + + cashback_percent = line.product_id.x_manufacture.cashback_percent or 0 + if cashback_percent <= 0: + continue + + + if line.vendor_id.id != 5571: + continue + + price_tax_excl = price + + if taxes: + tax = self.env['account.tax'].browse(taxes) + if tax.price_include: + price_tax_excl = price / (1 + (tax.amount / 100)) + else: + price_tax_excl = price + + line.amount_cashback = price_tax_excl * cashback_percent + # @api.onchange('vendor_id') # def onchange_vendor_id(self): # # TODO : need to change this logic @stephan diff --git a/indoteknik_custom/models/solr/apache_solr.py b/indoteknik_custom/models/solr/apache_solr.py index c2283421..21fb15d2 100644 --- a/indoteknik_custom/models/solr/apache_solr.py +++ b/indoteknik_custom/models/solr/apache_solr.py @@ -7,12 +7,12 @@ import time from odoo.tools.config import config _logger = logging.getLogger(__name__) -# _solr = pysolr.Solr('http://10.148.0.5:8983/solr/product/', always_commit=True, timeout=30) -# _variants_solr = pysolr.Solr('http://10.148.0.5:8983/solr/variants/', always_commit=True, timeout=30) -# _recommendation_solr = pysolr.Solr('http://10.148.0.5:8983/solr/recommendation/', always_commit=True, timeout=30) -_solr = pysolr.Solr('http://localhost:8983/solr/product/', always_commit=True, timeout=30) -_variants_solr = pysolr.Solr('http://localhost:8983/solr/variants/', always_commit=True, timeout=30) -_recommendation_solr = pysolr.Solr('http://localhost:8983/solr/recommendation/', always_commit=True, timeout=30) +_solr = pysolr.Solr('http://10.148.0.5:8983/solr/product/', always_commit=True, timeout=30) +_variants_solr = pysolr.Solr('http://10.148.0.5:8983/solr/variants/', always_commit=True, timeout=30) +_recommendation_solr = pysolr.Solr('http://10.148.0.5:8983/solr/recommendation/', always_commit=True, timeout=30) +# _solr = pysolr.Solr('http://35.219.88.139/solr/product/', always_commit=True, timeout=30) +# _variants_solr = pysolr.Solr('http://35.219.88.139/solr/variants/', always_commit=True, timeout=30) +# _recommendation_solr = pysolr.Solr('http://35.219.88.139/solr/recommendation/', always_commit=True, timeout=30) # _solr = pysolr.Solr('http://34.101.189.218:8983/solr/product/', always_commit=True, timeout=30) # for development only @@ -27,7 +27,7 @@ class ApacheSolr(models.Model): if env == 'development': url = 'http://localhost:8983/solr/' elif env == 'production': - url = 'http://locahost:8983/solr/' + url = 'http://34.101.189.218:8983/solr/' return pysolr.Solr(url + schema, always_commit=False, timeout=10) @@ -258,6 +258,7 @@ class ApacheSolr(models.Model): 'id': variant.id, 'display_name_s': variant.display_name, 'name_s': variant.name, + 'search_keywords_t': variant.display_name, 'default_code_s': variant.default_code or '', 'product_rating_f': variant.product_tmpl_id.virtual_rating, 'product_id_i': variant.id, @@ -269,6 +270,7 @@ class ApacheSolr(models.Model): 'tax_f': tax, 'stock_total_f': variant.qty_stock_vendor, 'weight_f': variant.product_tmpl_id.weight, + 'has_magento_b': variant.has_magento, 'attribute_set_id_i': variant.product_tmpl_id.x_attribute_set_id or 0, 'attribute_set_name_s': variant.product_tmpl_id.x_attribute_set_name or '', 'manufacture_id_i': variant.product_tmpl_id.x_manufacture.id or 0, diff --git a/indoteknik_custom/models/solr/product_product.py b/indoteknik_custom/models/solr/product_product.py index 7df56e57..a90bcb98 100644 --- a/indoteknik_custom/models/solr/product_product.py +++ b/indoteknik_custom/models/solr/product_product.py @@ -64,6 +64,7 @@ class ProductProduct(models.Model): 'id': variant.id, 'display_name_s': variant.display_name, 'name_s': variant.name, + 'search_keywords_t': variant.display_name, 'default_code_s': variant.default_code or '', 'product_rating_f': variant.product_tmpl_id.virtual_rating, 'product_id_i': variant.id, @@ -73,6 +74,7 @@ class ProductProduct(models.Model): 'image_mobile_s': ir_attachment.api_image('product.template', 'image_256', variant.product_tmpl_id.id), 'stock_total_f': variant.qty_free_bandengan, 'weight_f': variant.weight, + 'has_magento_b': variant.has_magento, 'attribute_set_id_i': variant.product_tmpl_id.x_attribute_set_id or 0, 'attribute_set_name_s': variant.product_tmpl_id.x_attribute_set_name or '', 'manufacture_id_i': variant.product_tmpl_id.x_manufacture.id or 0, diff --git a/indoteknik_custom/models/tukar_guling_po.py b/indoteknik_custom/models/tukar_guling_po.py index ae58d509..1ee10679 100644 --- a/indoteknik_custom/models/tukar_guling_po.py +++ b/indoteknik_custom/models/tukar_guling_po.py @@ -582,7 +582,23 @@ class TukarGulingPO(models.Model): ('group_id', '=', group.id), ('state', '=', 'done') ]) - bu_inputs = po_pickings.filtered(lambda p: p.picking_type_id.id == 28) + + product_ids = set(record.line_ids.mapped("product_id").ids) + + _logger.info("TG product_ids: %s", product_ids) + + def _get_moves(picking): + return picking.move_ids_without_package if picking.move_ids_without_package else picking.move_lines + + bu_inputs = po_pickings.filtered( + lambda p: p.picking_type_id.id == 28 and any( + m.product_id.id in product_ids + for m in _get_moves(p) + ) + ) + + _logger.info("BU INPUT dengan product sama: %s", bu_inputs.mapped("name")) + bu_puts = po_pickings.filtered(lambda p: p.picking_type_id.id == 75) else: raise UserError("Group ID tidak ditemukan pada BU Operations.") @@ -711,12 +727,26 @@ class TukarGulingPO(models.Model): # Ambil pasangannya di BU INPUT (asumsi urutan sejajar) sorted_bu_puts = sorted(bu_puts, key=lambda p: p.name) + # sorted_bu_inputs = sorted(bu_inputs, key=lambda p: p.name) + + # if bu_put_index >= len(sorted_bu_inputs): + # raise UserError("Tidak ditemukan pasangan BU INPUT untuk BU PUT yang dipilih.") + + # paired = [(sorted_bu_puts[bu_put_index], sorted_bu_inputs[bu_put_index])] sorted_bu_inputs = sorted(bu_inputs, key=lambda p: p.name) - if bu_put_index >= len(sorted_bu_inputs): - raise UserError("Tidak ditemukan pasangan BU INPUT untuk BU PUT yang dipilih.") + if not sorted_bu_inputs: + raise UserError( + "Tidak ditemukan BU INPUT yang memiliki product TG." + ) - paired = [(sorted_bu_puts[bu_put_index], sorted_bu_inputs[bu_put_index])] + paired = [(record.operations, sorted_bu_inputs[0])] + + _logger.info( + "🔗 Pairing BU PUT %s dengan BU INPUT %s", + record.operations.name, + sorted_bu_inputs[0].name + ) for bu_put, bu_input in paired: vrt = _create_return_from_picking(bu_put, bu_put_qty_map) diff --git a/indoteknik_custom/models/x_manufactures.py b/indoteknik_custom/models/x_manufactures.py index b4b61296..0c3bfa3b 100755 --- a/indoteknik_custom/models/x_manufactures.py +++ b/indoteknik_custom/models/x_manufactures.py @@ -50,6 +50,7 @@ class XManufactures(models.Model): # user_id = fields.Many2one('res.users', string='Responsible', domain="['|'('id', '=', 19), ('id', '=', 6)]", help="Siapa yang bertanggung jawab") user_id = fields.Many2one('res.users', string='Responsible', help="Siapa yang bertanggung jawab") override_vendor_id = fields.Many2one('res.partner', string='Override Vendor') + cashback_percent = fields.Float(string='Cashback Percent', default=0) def _compute_vendor_ids(self): for manufacture in self: diff --git a/indoteknik_custom/report/purchase_report.xml b/indoteknik_custom/report/purchase_report.xml index 54ac6193..81129dde 100644 --- a/indoteknik_custom/report/purchase_report.xml +++ b/indoteknik_custom/report/purchase_report.xml @@ -67,7 +67,7 @@ ADM. JAKARTA UTARA, DKI JAKARTA </t> <t t-else=""> - Jl. Bandengan Utara Komp A 8 B RT.<br/> + Jl. Bandengan Utara Komp A & B RT.<br/> Penjaringan, Kec. Penjaringan, Jakarta<br/> (BELAKANG INDOMARET) </t> @@ -106,7 +106,7 @@ <div style="display:flex; flex-direction:column; flex:1;"> <span style="font-weight:bold; margin-bottom:2px;"> <t t-esc="line_index + 1"/>. - <t t-if="line.product_id.id in [114360, 595346, 610166]"> + <t t-if="line.product_id.id in [114360, 595346, 610166, 420315]"> <t t-esc="line.name"/> </t> <t t-else=""> diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index 796e5275..7f553ddc 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -199,6 +199,7 @@ access_advance_payment_settlement,access.advance.payment.settlement,model_advanc access_advance_payment_usage_line,access.advance.payment.usage.line,model_advance_payment_usage_line,,1,1,1,1 access_advance_payment_create_bill,access.advance.payment.create.bill,model_advance_payment_create_bill,,1,1,1,1 access_create_reimburse_cab_wizard_user,create.reimburse.cab.wizard user,model_create_reimburse_cab_wizard,,1,1,1,1 +access_advance_payment_cancel_wizard,advance.payment.cancel.wizard,model_advance_payment_cancel_wizard,,1,1,1,1 access_purchasing_job_seen,purchasing.job.seen,model_purchasing_job_seen,,1,1,1,1 access_tukar_guling_all_users,tukar.guling.all.users,model_tukar_guling,base.group_user,1,1,1,1 diff --git a/indoteknik_custom/views/advance_payment_request.xml b/indoteknik_custom/views/advance_payment_request.xml index dd6370c7..7f422aa9 100644 --- a/indoteknik_custom/views/advance_payment_request.xml +++ b/indoteknik_custom/views/advance_payment_request.xml @@ -4,7 +4,7 @@ <field name="name">advance.payment.request.form</field> <field name="model">advance.payment.request</field> <field name="arch" type="xml"> - <form string="Advance Payment Request & Reimburse" duplicate="0"> + <form string="Advance Payment Request & Reimburse" duplicate="0" delete="false"> <header> <button name="action_realisasi_pum" type="object" @@ -18,7 +18,7 @@ type="object" string="Checking/Approval" class="btn-success" - attrs="{'invisible': [('status', 'in', ['approved','reject','draft'])]}"/> + attrs="{'invisible': [('status', 'in', ['approved','cancel','draft'])]}"/> <button name="action_confirm_payment" type="object" string="Konfirmasi Pembayaran" @@ -44,6 +44,11 @@ ('is_cab_visible', '=', True), ('type_request', '!=', 'reimburse') ]}"/> + <button name="action_open_cancel_wizard" + string="Cancel" + type="object" + class="btn-danger" + attrs="{'invisible': ['|',('status', 'in', ['draft', 'cancel']), ('status_pay_down_payment', '=', 'payment')]}"/> <field name="status" widget="statusbar" statusbar_visible="draft,pengajuan1,pengajuan2,pengajuan3,approved" statusbar_colors='{"reject":"red"}' @@ -51,7 +56,8 @@ </header> <sheet> <widget name="web_ribbon" title="Payment" attrs="{'invisible': ['|', ('status_pay_down_payment', '!=', 'payment'), ('status', '=', 'draft')]}"/> - <widget name="web_ribbon" title="Pending" bg_color="bg-danger" attrs="{'invisible': ['|', ('status_pay_down_payment', '!=', 'pending'), ('status', '=', 'draft')]}"/> + <widget name="web_ribbon" title="Pending" bg_color="bg-warning" attrs="{'invisible': ['|', ('status_pay_down_payment', '!=', 'pending'), ('status', '=', 'draft')]}"/> + <widget name="web_ribbon" title="Cancel" bg_color="bg-danger" attrs="{'invisible': ['|', ('status_pay_down_payment', '!=', 'cancel'), ('status', '=', 'draft')]}"/> <div class="oe_button_box" name="button_box" style="right: 150px;"> <field name="has_settlement" invisible="1"/> <button name="action_realisasi_pum" @@ -108,9 +114,10 @@ <field name="approved_by" readonly="1"/> <field name="create_date" readonly="1"/> <field name="status_pay_down_payment" - readonly="1" + readonly="1" decoration-success="status_pay_down_payment == 'payment'" - decoration-danger="status_pay_down_payment == 'pending'" + decoration-warning="status_pay_down_payment == 'pending'" + decoration-danger="status_pay_down_payment == 'cancel'" widget="badge" invisible = "1"/> </group> <group string="Bukti Transfer"> @@ -194,7 +201,7 @@ <field name="name">advance.payment.request.tree</field> <field name="model">advance.payment.request</field> <field name="arch" type="xml"> - <tree> + <tree delete="false"> <field name="number"/> <field name="applicant_name"/> <field name="nominal"/> @@ -207,7 +214,8 @@ <field name="status_pay_down_payment" readonly="1" decoration-success="status_pay_down_payment == 'payment'" - decoration-danger="status_pay_down_payment == 'pending'" + decoration-warning="status_pay_down_payment == 'pending'" + decoration-danger="status_pay_down_payment == 'cancel'" widget="badge"/> <field name="days_remaining" readonly="1" widget="badge" optional="hide"/> <field name="estimated_return_date" widget="badge" optional="hide"/> @@ -316,4 +324,34 @@ <field name="view_id" ref="view_form_create_reimburse_cab_wizard"/> <field name="target">new</field> </record> + + <record id="view_advance_payment_cancel_wizard_form" model="ir.ui.view"> + <field name="name">advance.payment.cancel.wizard.form</field> + <field name="model">advance.payment.cancel.wizard</field> + <field name="arch" type="xml"> + <form string="Batalkan Pengajuan"> + <sheet> + <group> + <div class="alert alert-warning" role="alert" style="margin-bottom: 10px;"> + Apakah Anda yakin ingin membatalkan pengajuan ini? + Silakan isi alasan pembatalan di bawah ini. + </div> + </group> + <group> + <field name="reason"/> + </group> + </sheet> + <footer> + <button name="action_confirm_cancel" + string="Konfirmasi Cancel" + type="object" + class="btn-danger"/> + + <button string="Tutup" + class="btn-secondary" + special="cancel"/> + </footer> + </form> + </field> + </record> </odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/advance_payment_settlement.xml b/indoteknik_custom/views/advance_payment_settlement.xml index c2b6a26f..a8bf1de7 100644 --- a/indoteknik_custom/views/advance_payment_settlement.xml +++ b/indoteknik_custom/views/advance_payment_settlement.xml @@ -3,7 +3,7 @@ <field name="name">advance.payment.settlement.form</field> <field name="model">advance.payment.settlement</field> <field name="arch" type="xml"> - <form string="Advance Payment Settlement" duplicate="0"> + <form string="Advance Payment Settlement" duplicate="0" delete="false"> <header> <button name="action_cab" type="object" diff --git a/indoteknik_custom/views/price_group.xml b/indoteknik_custom/views/price_group.xml index 5db8756e..7fad8d8d 100644 --- a/indoteknik_custom/views/price_group.xml +++ b/indoteknik_custom/views/price_group.xml @@ -26,6 +26,8 @@ <field name="group6"/> <field name="group7"/> <field name="group8"/> + <field name="group9"/> + <field name="group10"/> </tree> </field> </record> @@ -48,6 +50,8 @@ <field name="group6"/> <field name="group7"/> <field name="group8"/> + <field name="group9"/> + <field name="group10"/> </group> </group> </sheet> diff --git a/indoteknik_custom/views/product_product.xml b/indoteknik_custom/views/product_product.xml index 1d04e708..ee03779f 100644 --- a/indoteknik_custom/views/product_product.xml +++ b/indoteknik_custom/views/product_product.xml @@ -20,6 +20,7 @@ <field name="qty_free_bandengan" optional="hide"/> <field name="qty_rpo" optional="hide"/> <field name="plafon_qty" optional="hide"/> + <!-- <field name="has_magento" optional="hide"/> --> </field> </field> </record> diff --git a/indoteknik_custom/views/product_public_category.xml b/indoteknik_custom/views/product_public_category.xml index a45e0a2e..c2ee154d 100755 --- a/indoteknik_custom/views/product_public_category.xml +++ b/indoteknik_custom/views/product_public_category.xml @@ -22,6 +22,7 @@ <field name="image" widget="image"/> <field name="sequence_frontend"/> <field name="parent_frontend_id"/> + <field name="short_desc"/> </xpath> <xpath expr="//form[1]/sheet[1]/div[1]/group[1]" position="after"> <notebook> diff --git a/indoteknik_custom/views/product_template.xml b/indoteknik_custom/views/product_template.xml index 1933a5d1..9fbf007a 100755 --- a/indoteknik_custom/views/product_template.xml +++ b/indoteknik_custom/views/product_template.xml @@ -78,6 +78,7 @@ <field name="inherit_id" ref="product.product_normal_form_view"/> <field name="arch" type="xml"> <field name="last_update_solr" position="after"> + <field name="has_magento"/> <field name="barcode_box" /> <field name="qty_pcs_box" /> <field name="clean_website_description" /> @@ -114,6 +115,7 @@ <field name="solr_flag"/> <field name="x_attribute_set_id"/> <field name="x_attribute_set_name"/> + <!-- <field name="has_magento"/> --> </field> </field> </record> @@ -127,6 +129,7 @@ <field name="usage"/> <field name="specification"/> <field name="material"/> + <field name="has_magento" /> </field> </field> </record> diff --git a/indoteknik_custom/views/purchase_order.xml b/indoteknik_custom/views/purchase_order.xml index 16b8bd44..59e317d2 100755 --- a/indoteknik_custom/views/purchase_order.xml +++ b/indoteknik_custom/views/purchase_order.xml @@ -105,6 +105,7 @@ <field name="amount_total" position="after"> <field name="total_margin"/> <field name="total_so_margin"/> + <field name="amount_cashback"/> <field name="total_percent_margin"/> <field name="total_so_percent_margin"/> </field> diff --git a/indoteknik_custom/views/purchasing_job.xml b/indoteknik_custom/views/purchasing_job.xml index 6b8baa53..8e1eb3b6 100644 --- a/indoteknik_custom/views/purchasing_job.xml +++ b/indoteknik_custom/views/purchasing_job.xml @@ -16,7 +16,8 @@ <field name="outgoing"/> <field name="status_apo" invisible="1"/> <field name="action"/> - <field name="note"/> + <field name="note" optional="hide"/> + <field name="note_detail"/> <field name="date_po" optional="hide"/> <field name="so_number"/> <field name="check_pj" invisible="1"/> @@ -58,7 +59,8 @@ <field name="outgoing"/> <field name="purchase_representative_id"/> <field name="vendor_id"/> - <field name="note"/> + <!-- <field name="note"/> --> + <field name="note_detail"/> </group> </group> </sheet> diff --git a/indoteknik_custom/views/purchasing_job_state.xml b/indoteknik_custom/views/purchasing_job_state.xml index c7c40020..ca08e44c 100644 --- a/indoteknik_custom/views/purchasing_job_state.xml +++ b/indoteknik_custom/views/purchasing_job_state.xml @@ -8,7 +8,8 @@ <sheet> <group> <field name="status_apo" readonly="1"/> - <field name="note"/> + <field name="note" invisible="1"/> + <field name="note_detail"/> </group> </sheet> </form> diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index 23fbe155..c3df92ec 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -302,6 +302,7 @@ ] } "/> + <field name="amount_cashback"/> <field name="purchase_price_md" optional="hide"/> <field name="purchase_tax_id" attrs="{'readonly': [('parent.approval_status', '!=', False)]}" diff --git a/indoteknik_custom/views/x_manufactures.xml b/indoteknik_custom/views/x_manufactures.xml index 02061251..b52fe795 100755 --- a/indoteknik_custom/views/x_manufactures.xml +++ b/indoteknik_custom/views/x_manufactures.xml @@ -82,6 +82,7 @@ <field name="x_negara_asal"/> <field name="x_short_desc"/> <field name="x_manufacture_level"/> + <field name="cashback_percent" widget="percentage"/> <field name="x_produk_aksesoris_sparepart"/> <field name="cache_reset_status"/> <field name="parent_id"/> |
