summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMqdd <ahmadmiqdad27@gmail.com>2026-02-04 14:38:58 +0700
committerMqdd <ahmadmiqdad27@gmail.com>2026-02-04 14:38:58 +0700
commitd2a64b4e6023f0768d5c326c833fd5a9d8a11444 (patch)
tree98149f6da42a924b7ad1a1b01c50feeaa138a0bb
parent8bb3696e35dc122ea153566834a48ec0659e0101 (diff)
parentfb9b47c3fb5773782f84628764a01c5deb9be035 (diff)
Merge branch 'odoo-backup' of bitbucket.org:altafixco/indoteknik-addons into cr_renca_find
merge
-rw-r--r--indoteknik_api/controllers/api_v1/category.py15
-rw-r--r--indoteknik_custom/models/account_move.py84
-rw-r--r--indoteknik_custom/models/advance_payment_request.py62
-rw-r--r--indoteknik_custom/models/automatic_purchase.py3
-rw-r--r--indoteknik_custom/models/commision.py5
-rw-r--r--indoteknik_custom/models/price_group.py4
-rwxr-xr-xindoteknik_custom/models/product_public_category.py1
-rwxr-xr-xindoteknik_custom/models/product_template.py11
-rwxr-xr-xindoteknik_custom/models/purchase_order.py50
-rwxr-xr-xindoteknik_custom/models/purchase_order_line.py46
-rw-r--r--indoteknik_custom/models/purchasing_job.py4
-rw-r--r--indoteknik_custom/models/purchasing_job_multi_update.py17
-rw-r--r--indoteknik_custom/models/purchasing_job_state.py3
-rw-r--r--indoteknik_custom/models/refund_sale_order.py89
-rwxr-xr-xindoteknik_custom/models/sale_order.py13
-rw-r--r--indoteknik_custom/models/sale_order_line.py53
-rw-r--r--indoteknik_custom/models/solr/apache_solr.py16
-rw-r--r--indoteknik_custom/models/solr/product_product.py2
-rw-r--r--indoteknik_custom/models/tukar_guling_po.py38
-rwxr-xr-xindoteknik_custom/models/x_manufactures.py1
-rw-r--r--indoteknik_custom/report/purchase_report.xml4
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv1
-rw-r--r--indoteknik_custom/views/advance_payment_request.xml52
-rw-r--r--indoteknik_custom/views/advance_payment_settlement.xml2
-rw-r--r--indoteknik_custom/views/price_group.xml4
-rw-r--r--indoteknik_custom/views/product_product.xml1
-rwxr-xr-xindoteknik_custom/views/product_public_category.xml1
-rwxr-xr-xindoteknik_custom/views/product_template.xml3
-rwxr-xr-xindoteknik_custom/views/purchase_order.xml1
-rw-r--r--indoteknik_custom/views/purchasing_job.xml6
-rw-r--r--indoteknik_custom/views/purchasing_job_state.xml3
-rwxr-xr-xindoteknik_custom/views/sale_order.xml1
-rwxr-xr-xindoteknik_custom/views/x_manufactures.xml1
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 &amp; 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 &amp; Reimburse" duplicate="0">
+ <form string="Advance Payment Request &amp; 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"/>