diff options
| author | Azka Nathan <darizkyfaz@gmail.com> | 2025-07-11 15:27:51 +0700 |
|---|---|---|
| committer | Azka Nathan <darizkyfaz@gmail.com> | 2025-07-11 15:27:51 +0700 |
| commit | 887db07ff8a79fdbaeddc07b6b09ff169f428a6c (patch) | |
| tree | 802b919825785a9fb648408241df58048b0766ac | |
| parent | 3021a1d4836a47721500d03eeed80ba029334b98 (diff) | |
| parent | 575a7a506382487a625914a7bde9a18b20173cc6 (diff) | |
Merge branch 'odoo-backup' of bitbucket.org:altafixco/indoteknik-addons into odoo-backup
| -rwxr-xr-x | indoteknik_custom/__manifest__.py | 1 | ||||
| -rw-r--r-- | indoteknik_custom/models/account_move.py | 97 | ||||
| -rw-r--r-- | indoteknik_custom/models/dunning_run.py | 20 | ||||
| -rw-r--r-- | indoteknik_custom/models/sale_order_line.py | 1 | ||||
| -rw-r--r-- | indoteknik_custom/views/ir_sequence.xml | 2 | ||||
| -rw-r--r-- | indoteknik_custom/views/mail_template_invoice_reminder.xml | 49 |
6 files changed, 152 insertions, 18 deletions
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index 17cec7b6..21afc26f 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -97,6 +97,7 @@ 'views/mail_template_po.xml', 'views/mail_template_efaktur.xml', 'views/mail_template_invoice_po.xml', + 'views/mail_template_invoice_reminder.xml', 'views/price_group.xml', 'views/mrp_production.xml', 'views/apache_solr.xml', diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index b6627867..5ac1c6e5 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -8,12 +8,15 @@ import PyPDF2 import os import re from terbilang import Terbilang +from collections import defaultdict +from odoo.tools.misc import formatLang _logger = logging.getLogger(__name__) class AccountMove(models.Model): _inherit = 'account.move' + _description = 'Account Move' invoice_day_to_due = fields.Integer(string="Day to Due", compute="_compute_invoice_day_to_due") bill_day_to_due = fields.Date(string="Day to Due", compute="_compute_bill_day_to_due") date_send_fp = fields.Datetime(string="Tanggal Kirim Faktur Pajak") @@ -72,21 +75,87 @@ class AccountMove(models.Model): bill_id = fields.Many2one('account.move', string='Vendor Bill', domain=[('move_type', '=', 'in_invoice')], help='Bill asal dari proses reklas ini') down_payment = fields.Boolean('Down Payments?') + def send_due_invoice_reminder(self): + today = fields.Date.today() + target_dates = [ + today - timedelta(days=7), + today - timedelta(days=3), + today, + today + timedelta(days=3), + today + timedelta(days=7), + ] + + partner = self.env['res.partner'].search([('name', 'ilike', 'FLYNINDO MEGA PERSADA')], limit=1) + if not partner: + _logger.info("Partner tidak ditemukan.") + return + + invoices = self.env['account.move'].search([ + ('move_type', '=', 'out_invoice'), + ('state', '=', 'posted'), + ('payment_state', 'not in', ['paid','in_payment', 'reversed']), + ('invoice_date_due', 'in', target_dates), + ('partner_id', '=', partner.id), + ]) + + _logger.info(f"Invoices tahap 1: {invoices}") + + invoices = invoices.filtered( + lambda inv: inv.invoice_payment_term_id and 'tempo' in (inv.invoice_payment_term_id.name or '').lower() + ) + _logger.info(f"Invoices tahap 2: {invoices}") + + if not invoices: + _logger.info(f"Tidak ada invoice yang due untuk partner: {partner.name}") + return + + grouped = {} + for inv in invoices: + grouped.setdefault(inv.partner_id, []).append(inv) + + template = self.env.ref('indoteknik_custom.mail_template_invoice_due_reminder') + + for partner, invs in grouped.items(): + if not partner.email: + _logger.info(f"Partner {partner.name} tidak memiliki email") + continue + + invoice_table_rows = "" + for inv in invs: + days_to_due = (inv.invoice_date_due - today).days if inv.invoice_date_due else 0 + invoice_table_rows += f""" + <tr> + <td>{inv.name}</td> + <td>{fields.Date.to_string(inv.invoice_date) or '-'}</td> + <td>{fields.Date.to_string(inv.invoice_date_due) or '-'}</td> + <td>{days_to_due}</td> + <td>{formatLang(self.env, inv.amount_total, currency_obj=inv.currency_id)}</td> + <td>{inv.ref or '-'}</td> + </tr> + """ + + subject = f"Reminder Invoice Due - {partner.name}" + body_html = re.sub( + r"<tbody[^>]*>.*?</tbody>", + f"<tbody>{invoice_table_rows}</tbody>", + template.body_html, + flags=re.DOTALL + ).replace('${object.name}', partner.name) \ + .replace('${object.partner_id.name}', partner.name) + # .replace('${object.email}', partner.email or '') + + values = { + 'subject': subject, + 'email_to': 'andrifebriyadiputra@gmail.com', # Ubah ke partner.email untuk produksi + 'email_from': 'finance@indoteknik.co.id', + 'body_html': body_html, + } + + _logger.info(f"VALUES: {values}") + + template.send_mail(invs[0].id, force_send=True, email_values=values) + _logger.info(f"Reminder terkirim ke {partner.name} ({values['email_to']}) → {len(invs)} invoice") - # def name_get(self): - # result = [] - # for move in self: - # if move.move_type == 'entry': - # # Jika masih draft, tampilkan 'Draft CAB' - # if move.state == 'draft': - # label = 'Draft CAB' - # else: - # label = move.name - # result.append((move.id, label)) - # else: - # # Untuk invoice dan lainnya, pakai default - # result.append((move.id, move.display_name)) - # return result @api.onchange('invoice_date') def _onchange_invoice_date(self): diff --git a/indoteknik_custom/models/dunning_run.py b/indoteknik_custom/models/dunning_run.py index bb53fc0c..5a6aebac 100644 --- a/indoteknik_custom/models/dunning_run.py +++ b/indoteknik_custom/models/dunning_run.py @@ -92,10 +92,23 @@ class DunningRun(models.Model): ('move_type', '=', 'out_invoice'), ('state', '=', 'posted'), ('partner_id', '=', partner.id), - # ('amount_residual_signed', '>', 0), ('date_kirim_tukar_faktur', '=', False), ] - invoices = self.env['account.move'].search(query, order='invoice_date') + invoices = self.env['account.move'].search(query) + + # sort full berdasarkan tahun, bulan, nomor + def invoice_key(x): + try: + parts = x.name.split('/') + tahun = int(parts[1]) + bulan = int(parts[2]) + nomor = int(parts[3]) + return (tahun, bulan, nomor) + except Exception: + return (0, 0, 0) + + invoices = sorted(invoices, key=invoice_key) + count = 0 for invoice in invoices: self.env['dunning.run.line'].create([{ @@ -123,8 +136,9 @@ class DunningRunLine(models.Model): _name = 'dunning.run.line' _description = 'Dunning Run Line' # _order = 'dunning_id, id' - _order = 'invoice_id desc, id' + _order = 'invoice_number asc, id' + invoice_number = fields.Char('Invoice Number', related='invoice_id.name') dunning_id = fields.Many2one('dunning.run', string='Dunning Ref', required=True, ondelete='cascade', index=True, copy=False) partner_id = fields.Many2one('res.partner', string='Customer') invoice_id = fields.Many2one('account.move', string='Invoice') diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py index 291940ed..2a0160e8 100644 --- a/indoteknik_custom/models/sale_order_line.py +++ b/indoteknik_custom/models/sale_order_line.py @@ -5,6 +5,7 @@ from datetime import datetime, timedelta class SaleOrderLine(models.Model): _inherit = 'sale.order.line' + item_margin = fields.Float('Margin', compute='compute_item_margin', help="Total Margin in Sales Order Header") item_before_margin = fields.Float('Before Margin', compute='compute_item_before_margin', help="Total Margin in Sales Order Header") diff --git a/indoteknik_custom/views/ir_sequence.xml b/indoteknik_custom/views/ir_sequence.xml index a0f5fc6b..d9b93ff3 100644 --- a/indoteknik_custom/views/ir_sequence.xml +++ b/indoteknik_custom/views/ir_sequence.xml @@ -154,7 +154,7 @@ <record id="sequence_approval_payment_term" model="ir.sequence"> <field name="name">Approval Payment Term</field> <field name="code">approval.payment.term</field> - <field name="prefix">APP/%(year)s/</field> + <field name="prefix">APT/%(year)s/</field> <field name="padding">5</field> <field name="number_next">1</field> <field name="number_increment">1</field> diff --git a/indoteknik_custom/views/mail_template_invoice_reminder.xml b/indoteknik_custom/views/mail_template_invoice_reminder.xml new file mode 100644 index 00000000..8b3b9880 --- /dev/null +++ b/indoteknik_custom/views/mail_template_invoice_reminder.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <data noupdate="0"> + <record id="mail_template_invoice_due_reminder" model="mail.template"> + <field name="name">Invoice Reminder: Due Date Notification</field> + <field name="model_id" ref="account.model_account_move"/> + <field name="subject">Reminder Invoice Due - ${object.name}</field> + <field name="email_from">finance@indoteknik.co.id</field> + <field name="email_to">andrifebriyadiputra@gmail.com</field> + <field name="body_html" type="html"> + <div> + <p><b>Dear ${object.name},</b></p> + + <p>Berikut adalah daftar invoice Anda yang mendekati atau telah jatuh tempo:</p> + + <table border="1" cellpadding="6" cellspacing="0" style="border-collapse: collapse; width: 100%;"> + <thead> + <tr style="background-color: #f2f2f2;" align="left"> + <th>Invoice Number</th> + <th>Tanggal Invoice</th> + <th>Jatuh Tempo</th> + <th>Sisa Hari</th> + <th>Total</th> + <th>Referensi</th> + </tr> + </thead> + <tbody> + </tbody> + </table> + + <p>Mohon bantuan dan kerjasamanya agar tetap bisa bekerjasama dengan baik</p> + <p>Terima Kasih.</p> + <br/> + <br/> + <p><b>Best Regards, + <br/> + <br/> + Widya R.<br/> + Dept. Finance<br/> + PT. INDOTEKNIK DOTCOM GEMILANG</b><br/> + <img src="https://erp.indoteknik.com/api/image/ir.attachment/datas/2135765" alt="Indoteknik" style="max-width: 18%; height: auto;"></img><br/> + +62-857-1697-0374 | finance@indoteknik.co.id</p> + + </div> + </field> + <field name="auto_delete" eval="True"/> + </record> + </data> +</odoo> |
