summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIT Fixcomart <it@fixcomart.co.id>2025-08-21 15:39:31 +0000
committerIT Fixcomart <it@fixcomart.co.id>2025-08-21 15:39:31 +0000
commit1d5bd9c3b7c89eefe8a06e21ec5a53af3e72b4bb (patch)
treebecff9838f92c9ead50db31cea16eebb469ea2a7
parent4b549234856b810bd99f8b1e18e01da90ccdc1e1 (diff)
parent3f28815704346d81e42ea03a95f591ef1131a622 (diff)
Merged in reminder-tempo-v2 (pull request #391)
Reminder tempo v2
-rw-r--r--indoteknik_custom/models/account_move.py131
-rw-r--r--indoteknik_custom/models/res_partner.py8
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv4
-rw-r--r--indoteknik_custom/views/account_move.xml40
-rw-r--r--indoteknik_custom/views/res_partner.xml5
5 files changed, 180 insertions, 8 deletions
diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py
index 94774f0f..a211d739 100644
--- a/indoteknik_custom/models/account_move.py
+++ b/indoteknik_custom/models/account_move.py
@@ -99,6 +99,12 @@ class AccountMove(models.Model):
reminder_sent_date = fields.Date(string="Tanggal Reminder Terkirim")
+ customer_promise_date = fields.Date(
+ string="Janji Bayar",
+ help="Tanggal janji bayar dari customer setelah reminder dikirim.",
+ tracking=True
+ )
+
def compute_partial_payment(self):
for move in self:
if move.amount_total_signed > 0 and move.amount_residual_signed > 0 and move.payment_state == 'partial':
@@ -121,6 +127,36 @@ class AccountMove(models.Model):
else:
move.payment_date = False
+ def action_sync_promise_date(self):
+ self.ensure_one()
+ if not self.customer_promise_date:
+ raise UserError("Isi Janji Bayar terlebih dahulu sebelum melakukan sinkronisasi.")
+
+ other_invoices = self.env['account.move'].search([
+ ('id', '!=', self.id),
+ ('partner_id', '=', self.partner_id.id),
+ ('invoice_date_due', '=', self.invoice_date_due),
+ ('move_type', '=', 'out_invoice'),
+ ('state', '=', 'posted'),
+ ('date_terima_tukar_faktur', '!=', False)
+ ])
+ lines = []
+ for inv in other_invoices:
+ lines.append((0, 0, {'invoice_id': inv.id, 'sync_check': True})) # default dicentang semua
+
+ wizard = self.env['sync.promise.date.wizard'].create({
+ 'invoice_id': self.id,
+ 'line_ids': lines,
+ })
+
+ return {
+ 'name': 'Sync Janji Bayar',
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'sync.promise.date.wizard',
+ 'view_mode': 'form',
+ 'res_id': wizard.id,
+ 'target': 'new',
+ }
def send_due_invoice_reminder(self):
today = fields.Date.today()
@@ -168,6 +204,24 @@ class AccountMove(models.Model):
_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
+ if today <= earliest_promise:
+ _logger.info(
+ f"Skip reminder untuk {partner.name} karena ada Janji Bayar sampai {earliest_promise}"
+ )
+ continue
+
+ emails = []
+ # 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
+ # cek parent hanya dengan flag dont_sent_reminder_inv_parent
+ if not partner.dont_sent_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),
@@ -175,12 +229,8 @@ class AccountMove(models.Model):
('email', '!=', False),
])
_logger.info(f"Email Reminder Child {reminder_contacts}")
-
- # if not reminder_contacts:
- # _logger.info(f"Partner {partner.name} tidak memiliki email yang sudah ceklis reminder")
- # continue
-
- emails = list(filter(None, [partner.email])) + reminder_contacts.mapped('email')
+
+ emails += reminder_contacts.mapped('email')
if reminder_contacts:
_logger.info(f"Email Reminder Child {reminder_contacts}")
else:
@@ -689,4 +739,71 @@ class AccountMove(models.Model):
'date_efaktur_exported': datetime.utcnow(),
})
- return response \ No newline at end of file
+ return response
+
+class SyncPromiseDateWizard(models.TransientModel):
+ _name = "sync.promise.date.wizard"
+ _description = "Sync Janji Bayar Wizard"
+
+ invoice_id = fields.Many2one('account.move', string="Invoice Utama", required=True)
+ promise_date = fields.Date(string="Janji Bayar", related="invoice_id.customer_promise_date", readonly=True)
+ line_ids = fields.One2many('sync.promise.date.wizard.line', 'wizard_id', string="Invoices Terkait")
+
+ def action_check_all(self):
+ for line in self.line_ids:
+ line.sync_check = True
+ return {
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'sync.promise.date.wizard',
+ 'view_mode': 'form',
+ 'res_id': self.id,
+ 'target': 'new',
+ }
+
+ def action_uncheck_all(self):
+ for line in self.line_ids:
+ line.sync_check = False
+ return {
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'sync.promise.date.wizard',
+ 'view_mode': 'form',
+ 'res_id': self.id,
+ 'target': 'new',
+ }
+
+ def action_confirm(self):
+ self.ensure_one()
+ selected_lines = self.line_ids.filtered(lambda l: l.sync_check)
+ selected_invoices = selected_lines.mapped('invoice_id')
+
+ if not selected_invoices:
+ raise UserError("Tidak ada invoice dipilih untuk sinkronisasi.")
+
+ # Update hanya invoice yang dipilih
+ for inv in selected_invoices:
+ inv.write({'customer_promise_date': self.promise_date})
+ inv.message_post(
+ body=f"Janji Bayar {self.promise_date} disinkronkan dari invoice {self.invoice_id.name}."
+ )
+
+ # Log di invoice utama
+ self.invoice_id.message_post(
+ body=f"Janji Bayar {self.promise_date} disinkronkan ke {len(selected_invoices)} invoice lain: {', '.join(selected_invoices.mapped('name'))}."
+ )
+ return {'type': 'ir.actions.act_window_close'}
+
+
+class SyncPromiseDateWizardLine(models.TransientModel):
+ _name = "sync.promise.date.wizard.line"
+ _description = "Sync Janji Bayar Wizard Line"
+
+ wizard_id = fields.Many2one('sync.promise.date.wizard', string="Wizard")
+ invoice_id = fields.Many2one('account.move', string="Invoice")
+ sync_check = fields.Boolean(string="Sync?")
+ invoice_name = fields.Char(related="invoice_id.name", string="Nomor Invoice", readonly=True)
+ invoice_date_due = fields.Date(related="invoice_id.invoice_date_due", string="Due Date", readonly=True)
+ invoice_day_to_due = fields.Integer(related="invoice_id.invoice_day_to_due", string="Day to Due", readonly=True)
+ new_invoice_day_to_due = fields.Integer(related="invoice_id.new_invoice_day_to_due", string="New Day Due", readonly=True)
+ date_terima_tukar_faktur = fields.Date(related="invoice_id.date_terima_tukar_faktur", string="Tanggal Terima Tukar Faktur", readonly=True)
+ amount_total = fields.Monetary(related="invoice_id.amount_total", string="Total", readonly=True)
+ currency_id = fields.Many2one(related="invoice_id.currency_id", readonly=True) \ No newline at end of file
diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py
index e5e382a1..08b04e7d 100644
--- a/indoteknik_custom/models/res_partner.py
+++ b/indoteknik_custom/models/res_partner.py
@@ -31,6 +31,14 @@ class ResPartner(models.Model):
string='Reminder Invoice?',
help='Centang jika kontak ini harus menerima email pengingat invoice.', default=False
)
+ dont_send_reminder_inv_parent = fields.Boolean(
+ string='Dont Send Reminder Invoices Parent?',
+ help='Centang jika kontak utama tidak perlu menerima sent Reminder Invoices Otomatis', default=False
+ )
+ dont_send_reminder_inv_all = fields.Boolean(
+ string='Dont Send Reminder Invoices to All?',
+ help='Centang jika semua kontak utama dan child tidak menerima sent Reminder Invoices', default=False
+ )
# informasi perusahaan
name_tempo = fields.Many2one('res.partner', string='Nama Perusahaan',tracking=True)
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index d6e44f9d..78b3dc0f 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -192,4 +192,6 @@ access_tukar_guling_line_all_users,tukar.guling.line.all.users,model_tukar_gulin
access_tukar_guling_po_all_users,tukar.guling.po.all.users,model_tukar_guling_po,base.group_user,1,1,1,1
access_tukar_guling_line_po_all_users,tukar.guling.line.po.all.users,model_tukar_guling_line_po,base.group_user,1,1,1,1
access_tukar_guling_mapping_koli_all_users,tukar.guling.mapping.koli.all.users,model_tukar_guling_mapping_koli,base.group_user,1,1,1,1
-access_purchase_order_update_date_wizard,access.purchase.order.update.date.wizard,model_purchase_order_update_date_wizard,base.group_user,1,1,1,1 \ No newline at end of file
+access_purchase_order_update_date_wizard,access.purchase.order.update.date.wizard,model_purchase_order_update_date_wizard,base.group_user,1,1,1,1
+access_sync_promise_date_wizard,access.sync.promise.date.wizard,model_sync_promise_date_wizard,base.group_user,1,1,1,1
+access_sync_promise_date_wizard_line,access.sync.promise.date.wizard.line,model_sync_promise_date_wizard_line,base.group_user,1,1,1,1 \ No newline at end of file
diff --git a/indoteknik_custom/views/account_move.xml b/indoteknik_custom/views/account_move.xml
index e5d1cf8a..b399d4c9 100644
--- a/indoteknik_custom/views/account_move.xml
+++ b/indoteknik_custom/views/account_move.xml
@@ -68,6 +68,14 @@
<field name="nomor_kwitansi"/>
<field name="down_payment"/>
</field>
+ <field name="website_id" position="after">
+ <field name="customer_promise_date"/>
+ <button name="action_sync_promise_date"
+ string="Sync Janji Bayar ke Invoice Lain"
+ type="object"
+ class="btn-primary"
+ help="Sync Janji Bayar Customer ke Invoices dengan jumlah Due Date yang sama"/>
+ </field>
<field name="to_check" position="after">
<field name="already_paid"/>
<field name="so_shipping_paid_by"/>
@@ -195,5 +203,37 @@
<field name="state">code</field>
<field name="code">action = records.export_faktur_to_xml()</field>
</record>
+
+ <record id="view_sync_promise_date_wizard_form" model="ir.ui.view">
+ <field name="name">sync.promise.date.wizard.form</field>
+ <field name="model">sync.promise.date.wizard</field>
+ <field name="arch" type="xml">
+ <form string="Sync Janji Bayar">
+ <group>
+ <field name="invoice_id" readonly="1"/>
+ <field name="promise_date" readonly="1"/>
+ </group>
+ <field name="line_ids">
+ <tree create="false" delete="false" editable="bottom">
+ <field name="sync_check"/>
+ <field name="invoice_name" readonly="1"/>
+ <field name="invoice_date_due" readonly="1"/>
+ <field name="invoice_day_to_due" readonly="1"/>
+ <field name="new_invoice_day_to_due" readonly="1"/>
+ <field name="date_terima_tukar_faktur" readonly="1"/>
+ <field name="amount_total" readonly="1"/>
+ </tree>
+ </field>
+
+ <button name="action_check_all" string="Check All" type="object" class="btn-secondary"/>
+ <button name="action_uncheck_all" string="Uncheck All" type="object" class="btn-secondary"/>
+
+ <footer>
+ <button name="action_confirm" string="Konfirmasi Sync" type="object" class="btn-primary"/>
+ <button string="Batal" class="btn-secondary" special="cancel"/>
+ </footer>
+ </form>
+ </field>
+ </record>
</data>
</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml
index b081f6f2..ca1a36de 100644
--- a/indoteknik_custom/views/res_partner.xml
+++ b/indoteknik_custom/views/res_partner.xml
@@ -87,6 +87,7 @@
<field name="use_so_approval" attrs="{'invisible': [('parent_id', '!=', False), ('company_type', '!=', 'company')]}" />
<field name="use_only_ready_stock" attrs="{'invisible': [('parent_id', '!=', False), ('company_type', '!=', 'company')]}" />
<field name="web_role" attrs="{'invisible': ['|', ('parent_id', '=', False), ('company_type', '=', 'company')]}" />
+ <field name="reminder_invoices" attrs="{'invisible': ['|', ('parent_id', '=', False), ('company_type', '=', 'company')]}"/>
</field>
<xpath expr="//field[@name='child_ids']/form//field[@name='name']" position="before">
<field name="parent_id" invisible="1" />
@@ -215,6 +216,10 @@
<field name="dokumen_laporan_keuangan" />
<field name="dokumen_ktp_dirut" />
</group>
+ <group string="Reminder Invoices" attrs="{'invisible': [('parent_id', '!=', False), ('company_type', '!=', 'company')]}">
+ <field name="dont_send_reminder_inv_parent"/>
+ <field name="dont_send_reminder_inv_all" />
+ </group>
</page>
<page string="Aging Info">
<group string="Aging Info">