diff options
| -rw-r--r-- | indoteknik_custom/models/advance_payment_request.py | 96 | ||||
| -rw-r--r-- | indoteknik_custom/models/keywords.py | 43 | ||||
| -rw-r--r-- | indoteknik_custom/models/price_group.py | 20 | ||||
| -rwxr-xr-x | indoteknik_custom/models/product_template.py | 31 | ||||
| -rwxr-xr-x | indoteknik_custom/models/purchase_pricelist.py | 7 | ||||
| -rwxr-xr-x | indoteknik_custom/models/sale_order.py | 2 | ||||
| -rwxr-xr-x | indoteknik_custom/security/ir.model.access.csv | 1 | ||||
| -rw-r--r-- | indoteknik_custom/views/account_move_line.xml | 3 | ||||
| -rw-r--r-- | indoteknik_custom/views/advance_payment_request.xml | 24 | ||||
| -rw-r--r-- | indoteknik_custom/views/advance_payment_settlement.xml | 14 |
10 files changed, 182 insertions, 59 deletions
diff --git a/indoteknik_custom/models/advance_payment_request.py b/indoteknik_custom/models/advance_payment_request.py index 8cadb1b6..039d18a5 100644 --- a/indoteknik_custom/models/advance_payment_request.py +++ b/indoteknik_custom/models/advance_payment_request.py @@ -155,6 +155,18 @@ class AdvancePaymentRequest(models.Model): compute='_compute_is_current_user_ap' ) + estimate_line_ids = fields.One2many('advance.payment.request.estimate.line', 'request_id', string='Rincian Estimasi') + + @api.constrains('nominal', 'estimate_line_ids') + def _check_nominal_vs_estimate_total(self): + for rec in self: + if rec.type_request == 'pum': + if not rec.estimate_line_ids: + raise UserError("Rincian estimasi wajib diisi untuk PUM. Silakan tambahkan rincian estimasi.") + total_estimate = sum(line.nominal for line in rec.estimate_line_ids) + if round(total_estimate, 2) != round(rec.nominal, 2): + raise UserError("Total estimasi harus sama dengan nominal PUM. Silakan sesuaikan rincian estimasi atau nominal PUM.") + @api.onchange('grand_total_reimburse', 'type_request') def _onchange_reimburse_line_update_nominal(self): if self.type_request == 'reimburse': @@ -751,7 +763,7 @@ class AdvancePaymentRequest(models.Model): pum_ids = self.search([ ('user_id', '=', user.id), - ('status', '!=', 'reject'), + ('status', '!=', 'cancel'), ('type_request', '=', 'pum') ]) @@ -911,6 +923,35 @@ class AdvancePaymentUsageLine(models.Model): compute='_compute_is_current_user_ap' ) + category_usage = fields.Selection([ + ('parkir', 'Parkir'), + ('tol', 'Tol'), + ('bbm', 'BBM'), + ('kuli', 'Kuli'), + ('konsumsi', 'Konsumsi'), + ('lain_lain', 'Lain-lain'), + ], string='Kategori System', compute='_compute_category_usage') + + @api.depends('account_id') + def _compute_category_usage(self): + for rec in self: + if not rec.account_id: + rec.category_usage = False + continue + name = rec.account_id.name.lower() + if 'bbm' in name or 'bahan bakar' in name: + rec.category_usage = 'bbm' + elif 'tol' in name: + rec.category_usage = 'tol' + elif 'parkir' in name: + rec.category_usage = 'parkir' + elif 'kuli' in name or 'bongkar' in name: + rec.category_usage = 'kuli' + elif 'konsumsi' in name or 'makan' in name or 'minum' in name: + rec.category_usage = 'konsumsi' + else: + rec.category_usage = 'lain_lain' + def _compute_is_current_user_ap(self): ap_user_ids = [23, 9468, 16729] is_ap = self.env.user.id in ap_user_ids @@ -1144,6 +1185,11 @@ class AdvancePaymentSettlement(models.Model): string="Is Current User AP", compute='_compute_is_current_user_ap' ) + pum_estimate_line_ids = fields.One2many( + related='pum_id.estimate_line_ids', + string='Rincian Estimasi PUM', + readonly=True + ) def _compute_is_current_user_ap(self): ap_user_ids = [23, 9468, 16729] @@ -1612,4 +1658,50 @@ class CreateReimburseCabWizard(models.TransientModel): 'type': 'ir.actions.act_window', 'res_id': move.id, 'target': 'current', - }
\ No newline at end of file + } + +class AdvancePaymentRequestEstimateLine(models.Model): + _name = 'advance.payment.request.estimate.line' + _description = 'Advance Payment Request Estimate Line' + + request_id = fields.Many2one('advance.payment.request', string='Request') + category_estimate = fields.Selection([ + ('parkir', 'Parkir'), + ('tol', 'Tol'), + ('bbm', 'BBM'), + ('kuli', 'Kuli'), + ('konsumsi', 'Konsumsi'), + ('lain_lain', 'Lain-lain'), + ], string='Kategori Estimasi', required=True) + description = fields.Text(string='Description', help='Deskripsi tambahan untuk estimasi biaya yang diperlukan.') + nominal = fields.Float(string='Nominal Estimasi', required=True, help='Masukkan nominal estimasi untuk kategori ini (tidak mesti akurat, hanya untuk gambaran umum).') + currency_id = fields.Many2one(related='request_id.currency_id') + + total_actual = fields.Float(string='Nominal Realisasi', compute='_compute_actual_data') + frequency = fields.Integer(string='Qty Realisasi', compute='_compute_actual_data') + + @api.depends('request_id.settlement_ids.penggunaan_line_ids.nominal', + 'request_id.settlement_ids.penggunaan_line_ids.account_id') + def _compute_actual_data(self): + for rec in self: + total_act = 0 + freq = 0 + if rec.request_id and rec.request_id.settlement_ids: + all_usage_lines = rec.request_id.settlement_ids.mapped('penggunaan_line_ids') + valid_lines = all_usage_lines.filtered(lambda l: l.account_id and l.category_usage) + planned_category = rec.request_id.estimate_line_ids.mapped('category_estimate') + if rec.category_estimate == 'lain_lain': + matched_lines = valid_lines.filtered( + lambda l: l.category_usage == 'lain_lain' or \ + l.category_usage not in planned_category + ) + else: + matched_lines = valid_lines.filtered( + lambda l: l.category_usage == rec.category_estimate + ) + + total_act = sum(matched_lines.mapped('nominal')) + freq = len(matched_lines) + rec.total_actual = total_act + rec.frequency = freq + diff --git a/indoteknik_custom/models/keywords.py b/indoteknik_custom/models/keywords.py index 5b7da705..3fa9dd72 100644 --- a/indoteknik_custom/models/keywords.py +++ b/indoteknik_custom/models/keywords.py @@ -133,7 +133,7 @@ class Keywords(models.Model): def _onchange_solr_flag(self): """Set solr_flag=2 when tracked fields change to trigger queue sync""" for record in self: - if not record.skip: + if len(record.product_ids) > 0: record.solr_flag = 2 def solr_flag_to_queue(self, limit=500): @@ -161,10 +161,18 @@ class Keywords(models.Model): return True def _sync_keywords_queue_callback(self): - """Callback method executed by apache.solr.queue - syncs keyword data to Solr""" - documents = [] + success_keywords = self.browse() + for keyword in self: + if not keyword.product_ids: + _logger.info( + 'Skipping Solr sync for keyword "%s" - no products found', + keyword.keywords + ) + continue + searchkey = (keyword.keywords or '').strip().lower().replace(' ', '-') + try: doc = { 'id': keyword.id, @@ -173,13 +181,19 @@ class Keywords(models.Model): 'url_s': keyword.url, 'product_ids_is': [p.product_tmpl_id.id for p in keyword.product_ids], } - documents.append(doc) + + solr.add([doc]) + + success_keywords |= keyword + except Exception as e: - _logger.error('failed %s', e) - _logger.error('doc data: %s', doc) + _logger.error( + "Solr sync failed for keyword ID %s: %s", + keyword.id, e + ) - if documents: - solr.add(documents) + if success_keywords: + success_keywords.write({'solr_flag': 0}) return True @@ -194,6 +208,11 @@ class Keywords(models.Model): documents = [] for keyword in keywords: + # Skip syncing if product count is 0 + if len(keyword.product_ids) == 0: + _logger.info('Skipping Solr sync for keyword "%s" - no products found', keyword.keywords) + continue + searchkey = (keyword.keywords or '').strip().lower().replace(' ', '-') try: doc = { @@ -223,10 +242,12 @@ class Keywords(models.Model): def write(self, vals): result = super().write(vals) - tracked_fields = ['keywords', 'category_id', 'product_ids'] + tracked_fields = ['keywords', 'category_id', 'product_ids', 'skip', 'name'] neded_sync = any(field in vals for field in tracked_fields) - if neded_sync and self.skip == False and len(self.product_ids) > 0: + if neded_sync: for record in self: - record.solr_flag = 2 + # Only flag for sync if there are products + if len(record.product_ids) > 0: + record.solr_flag = 2 return result diff --git a/indoteknik_custom/models/price_group.py b/indoteknik_custom/models/price_group.py index fce78fff..1a4f1bd6 100644 --- a/indoteknik_custom/models/price_group.py +++ b/indoteknik_custom/models/price_group.py @@ -10,16 +10,16 @@ class PriceGroup(models.Model): name = fields.Char(string='Name') pricelist_id = fields.Many2one('product.pricelist', string='Price List') - group1 = fields.Float(string='Kelompok 1 (%)') - group2 = fields.Float(string='Kelompok 2 (%)') - group3 = fields.Float(string='Kelompok 3 (%)') - group4 = fields.Float(string='Kelompok 4 (%)') - group5 = fields.Float(string='Kelompok 5 (%)') - 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 (%)') + group1 = fields.Float(string='Kelompok 1 (%)', digits=(16, 12)) + group2 = fields.Float(string='Kelompok 2 (%)', digits=(16, 12)) + group3 = fields.Float(string='Kelompok 3 (%)', digits=(16, 12)) + group4 = fields.Float(string='Kelompok 4 (%)', digits=(16, 12)) + group5 = fields.Float(string='Kelompok 5 (%)', digits=(16, 12)) + group6 = fields.Float(string='Kelompok 6 (%)', digits=(16, 12)) + group7 = fields.Float(string='Kelompok 7 (%)', digits=(16, 12)) + group8 = fields.Float(string='Kelompok 8 (%)', digits=(16, 12)) + group9 = fields.Float(string='Kelompok 9 (%)', digits=(16, 12)) + group10 = fields.Float(string='Kelompok 10 (%)', digits=(16, 12)) def collect_price_group(self): PRICE_GROUP_ID = { diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py index 397bd06d..e10b4de2 100755 --- a/indoteknik_custom/models/product_template.py +++ b/indoteknik_custom/models/product_template.py @@ -94,7 +94,6 @@ class ProductTemplate(models.Model): if self.env.user.id not in users_in_group.mapped('id') and active_model == None: raise UserError('Hanya MD yang bisa membuat Product') result = super(ProductTemplate, self).create(vals) - self.env['product.product']._add_product_to_keywords(result) return result # def write(self, values): @@ -895,11 +894,6 @@ class ProductTemplate(models.Model): # Log changes self._log_field_changes_product(vals, old_values) - # Add product to keywords - keyword_trigger = ['name', 'website_description', 'unpublished'] - if any(field in vals for field in keyword_trigger): - for product in self: - self.env['product.product']._add_product_to_keywords(product) return result # def write(self, vals): @@ -946,26 +940,7 @@ class ProductProduct(models.Model): qr_code_variant = fields.Binary("QR Code Variant", compute='_compute_qr_code_variant') qty_pcs_box = fields.Float("Pcs Box") barcode_box = fields.Char("Barcode Box") - keyword_id = fields.Many2one('keywords', string='Keyword') - - def _add_product_to_keywords(self,product): - keywords_model = self.env['keywords'] - if not product: - return False - - for product in self: - match_keywords = keywords_model.search([ - '|', - ('name', 'ilike', product.name), - ('keywords', 'ilike', product.website_description) - ]) - - for kw in match_keywords.filtered(lambda k: not k.skip): - if not self.unpublished and product.id not in kw.product_ids.ids: - kw.write({'product_ids': [(4, product.id)]}) - - return True - + # keyword_id = fields.Many2one('keywords', string='Keyword') has_magento = fields.Boolean(string='Has Magento?', default=False, readonly=True) def generate_product_sla(self): @@ -988,7 +963,6 @@ class ProductProduct(models.Model): if self.env.user.id not in users_in_group.mapped('id') and active_model == None: raise UserError('Hanya MD yang bisa membuat Product') result = super(ProductProduct, self).create(vals) - self._add_product_to_keywords(result) return result # def write(self, values): @@ -1355,9 +1329,6 @@ class ProductProduct(models.Model): ] # pake ini kalau mau Cek semua field # if vals: - trigger_fields = ['name', 'website_description', 'unpublished'] - if any(f in vals for f in trigger_fields): - self._add_product_to_keywords(vals) if any(field in vals for field in tracked_fields): old_values = self._collect_old_values(vals) result = super().write(vals) diff --git a/indoteknik_custom/models/purchase_pricelist.py b/indoteknik_custom/models/purchase_pricelist.py index b3a473b6..83e06f55 100755 --- a/indoteknik_custom/models/purchase_pricelist.py +++ b/indoteknik_custom/models/purchase_pricelist.py @@ -118,15 +118,16 @@ class PurchasePricelist(models.Model): product_domain = [('product_id', '=', rec.product_id.id)] markup_pricelist = price_group['markup'].pricelist_id - base_price = price_incl + (price_incl * markup_percentage / 100) + # base_price = price_incl + (price_incl * markup_percentage / 100) + base_price = round(price_incl + (price_incl * markup_percentage / 100), 12) base_prod_pricelist = self.env['product.pricelist.item'].search(product_domain + [('pricelist_id', '=', markup_pricelist.id)], limit=1) base_prod_pricelist.fixed_price = base_price tier_percentages = [price_group[f'tier_{i}'][product_group] for i in range(1, 6)] for i, tier_percentage in enumerate(tier_percentages): tier_pricelist = price_group[f'tier_{i + 1}'].pricelist_id - tier_price = price_incl + (price_incl * tier_percentage / 100) - tier_perc = (base_price - tier_price) / base_price * 100 + tier_price = round(price_incl + (price_incl * tier_percentage / 100), 12) + tier_perc = round((base_price - tier_price) / base_price * 100, 12) tier_prod_pricelist = self.env['product.pricelist.item'].search(product_domain + [('pricelist_id', '=', tier_pricelist.id)], limit=1) tier_prod_pricelist.price_discount = tier_perc diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 90cd5fa2..e6fc4732 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -647,7 +647,7 @@ class SaleOrder(models.Model): def _get_biteship_courier_codes(self): return [ - 'gojek','grab','deliveree','lalamove','jne','ninja','lion','rara','sicepat','jnt','pos','idexpress','rpx','wahana','jdl','anteraja','sap','paxel','borzo' + 'gojek','grab','deliveree','lalamove','jne','ninja','lion','rara','sicepat','jnt','idexpress','rpx','wahana','jdl','anteraja','sap','paxel','borzo' ] @api.onchange('carrier_id') diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index 4ffefc68..b6583ed5 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -200,6 +200,7 @@ access_advance_payment_usage_line,access.advance.payment.usage.line,model_advanc 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_advance_payment_request_estimate_line,advance.payment.request.estimate.line,model_advance_payment_request_estimate_line,,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/account_move_line.xml b/indoteknik_custom/views/account_move_line.xml index 838596c8..346494f3 100644 --- a/indoteknik_custom/views/account_move_line.xml +++ b/indoteknik_custom/views/account_move_line.xml @@ -9,6 +9,9 @@ <!-- <xpath expr="//page[@id='aml_tab']/field[@name='line_ids']" position="attributes"> <attribute name="attrs">{'readonly': [('refund_id','!=',False)]}</attribute> </xpath> --> + <xpath expr="//field[@name='line_ids']/tree/field[@name='credit']" position="after"> + <field name="date_maturity" optional="hide"/> + </xpath> <xpath expr="//page[@id='aml_tab']/field[@name='line_ids']/tree/field[@name='currency_id']" position="before"> <field name="is_required" invisible="1"/> </xpath> diff --git a/indoteknik_custom/views/advance_payment_request.xml b/indoteknik_custom/views/advance_payment_request.xml index 340e0caf..4faf905e 100644 --- a/indoteknik_custom/views/advance_payment_request.xml +++ b/indoteknik_custom/views/advance_payment_request.xml @@ -134,8 +134,28 @@ <br/> </group> </group> - <notebook attrs="{'invisible': [('type_request', '!=', 'reimburse')]}"> - <page string="Rincian Reimburse"> + <notebook> + <page string="Rincian Estimasi PUM" attrs="{'invisible': [('type_request', '!=', 'pum')]}"> + <p style="font-size: 12px; color: grey; font-style: italic">*Masukkan estimasi alokasi biaya sebagai gambaran rencana penggunaan dana, tidak harus diisi dengan nominal yang akurat</p> + <field name="estimate_line_ids"> + <tree> + <field name="category_estimate"/> + <field name="description"/> + <field name="nominal" sum="Total"/> + <field name="currency_id" invisible="1"/> + </tree> + <form> + <group col="2"> + <field name="request_id" invisible="1"/> + <field name="category_estimate"/> + <field name="description" placeholder="Deskripsi tambahan untuk rincian estimasi..."/> + <field name="nominal"/> + <field name="currency_id" invisible="1"/> + </group> + </form> + </field> + </page> + <page string="Rincian Reimburse" attrs="{'invisible': [('type_request', '!=', 'reimburse')]}"> <field name="reimburse_line_ids"> <tree> <field name="sequence" widget="handle"/> diff --git a/indoteknik_custom/views/advance_payment_settlement.xml b/indoteknik_custom/views/advance_payment_settlement.xml index a8bf1de7..352c5b96 100644 --- a/indoteknik_custom/views/advance_payment_settlement.xml +++ b/indoteknik_custom/views/advance_payment_settlement.xml @@ -118,12 +118,26 @@ <group string="Finance"> <field name="is_current_user_ap" invisible="1"/> <field name="account_id" attrs="{'readonly': [('is_current_user_ap', '=', False)]}"/> + <field name="category_usage" invisible="1"/> <field name="done_attachment" attrs="{'readonly': [('is_current_user_ap', '=', False)]}"/> </group> </group> </form> </field> </page> + <page string="Rincian Estimasi PUM"> + <p style="font-size: 12px; color: grey; font-style: italic">*Rincian estimasi PUM ini hanya sebagai gambaran umum untuk realisasi yang dilakukan, tidak harus diisi dengan nominal yang akurat.</p> + <field name="pum_estimate_line_ids" nolabel="1"> + <tree> + <field name="category_estimate"/> + <field name="description"/> + <field name="nominal" sum="Total Estimasi"/> + <field name="frequency"/> + <field name="total_actual" sum="Total Actual"/> + <field name="currency_id" invisible="1"/> + </tree> + </field> + </page> </notebook> <div style="text-align:right;"> |
