diff options
| author | Azka Nathan <darizkyfaz@gmail.com> | 2025-07-18 09:25:57 +0700 |
|---|---|---|
| committer | Azka Nathan <darizkyfaz@gmail.com> | 2025-07-18 09:25:57 +0700 |
| commit | 10e171ea5389873fea3fb13c90242b322a37a990 (patch) | |
| tree | 9288e4c9693cb5ea1a3d18e66e0bb723f9be5133 /fixco_custom/models/upload_bills.py | |
| parent | 66b6b5863a15377c91300079026b11e7f81d60e4 (diff) | |
On change product otomatis terisi di requisition
Create bills by search PO & SKU
Create bills by upload
Diffstat (limited to 'fixco_custom/models/upload_bills.py')
| -rw-r--r-- | fixco_custom/models/upload_bills.py | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/fixco_custom/models/upload_bills.py b/fixco_custom/models/upload_bills.py new file mode 100644 index 0000000..0c037f3 --- /dev/null +++ b/fixco_custom/models/upload_bills.py @@ -0,0 +1,195 @@ +from odoo import models, fields, api, _ +from datetime import datetime +import base64 +import xlrd +from odoo.exceptions import ValidationError, UserError +import requests +import json +import hmac +from hashlib import sha256 + +class UploadBills(models.Model): + _name = "upload.bills" + _description = "Upload Bills" + _order = "create_date desc" + _rec_name = "number" + + bills_lines = fields.One2many('upload.bills.line', 'upload_bills_id', + string='Lines', copy=False, auto_join=True) + number = fields.Char('Number', copy=False) + date_upload = fields.Datetime('Upload Date', copy=False) + user_id = fields.Many2one('res.users', 'Created By', default=lambda self: self.env.user.id) + excel_file = fields.Binary('Excel File', attachment=True) + filename = fields.Char('File Name') + + @api.model + def create(self, vals): + vals['number'] = self.env['ir.sequence'].next_by_code('upload.bills') or '/' + return super().create(vals) + + def action_import_excel(self): + self.ensure_one() + if not self.excel_file: + raise ValidationError(_("Please upload an Excel file first.")) + + try: + file_content = base64.b64decode(self.excel_file) + workbook = xlrd.open_workbook(file_contents=file_content) + sheet = workbook.sheet_by_index(0) + except Exception: + raise ValidationError(_("Invalid Excel file format.")) + + if sheet.ncols < 3: + raise ValidationError(_("Excel format tidak valid. Minimal ada 3 kolom: No BU IN, Tanggal, dan Faktur Pajak.")) + + rows_data = [] + for row_idx in range(sheet.nrows): + try: + no_bu = str(sheet.cell(row_idx, 0).value).strip() + tanggal_raw = sheet.cell(row_idx, 1).value + faktur_pajak = str(sheet.cell(row_idx, 2).value).strip() + + if isinstance(tanggal_raw, float): + tanggal = datetime(*xlrd.xldate_as_tuple(tanggal_raw, workbook.datemode)).date() + else: + tanggal = datetime.strptime(tanggal_raw, '%Y-%m-%d').date() + + rows_data.append({ + 'row_num': row_idx + 1, + 'no_bu': no_bu, + 'date': tanggal, + 'faktur_pajak': faktur_pajak, + }) + except Exception: + continue + + faktur_list = [row['faktur_pajak'] for row in rows_data] + existing_faktur = set() + no_bu_list = [row['no_bu'] for row in rows_data] + existing_no_bu = set() + + chunk_size = 500 + for i in range(0, len(faktur_list), chunk_size): + chunk_faktur = faktur_list[i:i + chunk_size] + chunk_no_bu = no_bu_list[i:i + chunk_size] + + existing_lines = self.env['upload.bills.line'].search([ + '|', + ('faktur_pajak', 'in', chunk_faktur), + ('no_bu', 'in', chunk_no_bu) + ]) + + existing_faktur.update(existing_lines.mapped('faktur_pajak')) + existing_no_bu.update(existing_lines.mapped('no_bu')) + + duplicate_rows = [] + for row in rows_data: + if row['faktur_pajak'] in existing_faktur or row['no_bu'] in existing_no_bu: + duplicate_rows.append(str(row['row_num'])) + + if duplicate_rows: + raise ValidationError(_("Data duplikat ditemukan di baris: %s\nPeriksa 'No BU IN' atau 'Faktur Pajak' yang sudah pernah diupload.") % ", ".join(duplicate_rows)) + + line_vals_list = [] + for row in rows_data: + line_vals = { + 'no_bu': row['no_bu'], + 'date': row['date'], + 'faktur_pajak': row['faktur_pajak'], + 'upload_bills_id': self.id, + } + line_vals_list.append((0, 0, line_vals)) + + self.bills_lines.unlink() + self.write({'bills_lines': line_vals_list}) + + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'title': _('Success'), + 'message': _('Berhasil mengimpor %s baris dari Excel.') % len(line_vals_list), + 'sticky': False, + 'next': {'type': 'ir.actions.act_window_close'}, + } + } + + + def _show_notification(self, message): + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'title': _('Success'), + 'message': message, + 'sticky': False, + } + } + + def action_create_bills(self): + all_invoice_ids = [] + + for line in self.bills_lines: + bu_in = self.env['stock.picking'].search([ + ('name', '=', line.no_bu), + ('picking_type_code', '=', 'incoming') + ], limit=1) + + if not bu_in: + raise UserError(f"BU IN '{line.no_bu}' tidak ditemukan.") + + # Panggil pembuatan invoice + created_invoices = bu_in.action_create_invoice_from_mr() + + # Sinkron faktur dan tanggal ke account.move + if isinstance(created_invoices, dict) and 'res_id' in created_invoices: + # Satu invoice + invoice = self.env['account.move'].browse(created_invoices['res_id']) + invoice.write({ + 'faktur_pajak': line.faktur_pajak, + 'invoice_date': line.date + }) + invoice.action_post() + all_invoice_ids.append(invoice.id) + + elif isinstance(created_invoices, dict) and 'domain' in created_invoices: + # Banyak invoice + invoice_ids = created_invoices.get('domain', [])[0][2] or [] + invoices = self.env['account.move'].browse(invoice_ids) + invoices.write({ + 'faktur_pajak': line.faktur_pajak, + 'invoice_date': line.date + }) + invoices.action_post() + all_invoice_ids.extend(invoices.ids) + + else: + raise UserError("Gagal menemukan invoice yang baru dibuat.") + + # Tampilkan invoice(s) ke user + if not all_invoice_ids: + return {'type': 'ir.actions.act_window_close'} + + action = self.env.ref('account.action_move_in_invoice_type').read()[0] + if len(all_invoice_ids) == 1: + action.update({ + 'view_mode': 'tree,form', + 'res_id': all_invoice_ids, + }) + else: + action.update({ + 'domain': [('id', 'in', all_invoice_ids)], + 'view_mode': 'tree,form', + }) + return action + + +class UploadBillsLine(models.Model): + _name = "upload.bills.line" + _description = "Upload Bills Line" + _inherit = ['mail.thread'] + + upload_bills_id = fields.Many2one('upload.bills', string='Upload') + no_bu = fields.Char('No BU IN') + date = fields.Date('Date') + faktur_pajak = fields.Char('Faktur Pajak') |
