From 82c1232c08894dad3d6e326649785b5669a12077 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Fri, 9 Jan 2026 13:03:09 +0700 Subject: push --- fixco_custom/models/__init__.py | 3 ++- fixco_custom/models/account_move.py | 39 +++++++++++++++++++++++++++- fixco_custom/models/account_move_reversal.py | 9 +++++-- fixco_custom/models/account_payment.py | 11 ++++++++ fixco_custom/models/detail_order.py | 19 +++++++++++++- fixco_custom/models/sale.py | 2 ++ fixco_custom/models/stock_picking.py | 28 ++++++++++++++++++++ fixco_custom/views/account_move.xml | 23 ++++++++++++++++ fixco_custom/views/sale_order.xml | 2 ++ 9 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 fixco_custom/models/account_payment.py diff --git a/fixco_custom/models/__init__.py b/fixco_custom/models/__init__.py index 0068d32..de92dc0 100755 --- a/fixco_custom/models/__init__.py +++ b/fixco_custom/models/__init__.py @@ -38,4 +38,5 @@ from . import account_move_reversal from . import upload_cancel_picking from . import product_supplierinfo from . import queue_job -from . import purchase_order_multi_bills \ No newline at end of file +from . import purchase_order_multi_bills +from . import account_payment \ No newline at end of file diff --git a/fixco_custom/models/account_move.py b/fixco_custom/models/account_move.py index e40e65f..b96bed3 100644 --- a/fixco_custom/models/account_move.py +++ b/fixco_custom/models/account_move.py @@ -47,6 +47,29 @@ class AccountMove(models.Model): compute="_compute_need_refund", help="Flag otomatis kalau invoice sudah paid dan picking terkait di-return." ) + approval_refund = fields.Selection( + [('approved', 'Approved'), + ('rejected', 'Rejected'), + ('pending', 'Pending')], + string='Approval Refund', + copy=False, + tracking=True + ) + + def reject_refund(self): + if self.move_type == 'entry' and self.sale_id and self.ref.startswith('UANG MUKA PENJUALAN') and self.env.user.id in [9, 10, 15]: + self.approval_refund = 'rejected' + else: + raise UserError(_('Anda tidak memiliki akses untuk melakukan reject Uang Muka Penjualan!')) + + # def approve_refund(self): + # if self.move_type == 'entry' and self.sale_id and self.ref.startswith('UANG MUKA PENJUALAN') and self.env.user.id in [9, 10, 15]: + # self.approval_refund = 'approved' + # else: + # raise UserError(_('Anda tidak memiliki akses untuk melakukan approve Uang Muka Penjualan!')) + + def pending_refund(self): + self.approval_refund = 'pending' def queue_job_cancel_bill(self): QueueJob = self.env['queue.job'] @@ -73,7 +96,19 @@ class AccountMove(models.Model): 'res_id': move.id, } ]) - + + def button_draft(self): + if self.env.user.id not in [24, 13, 10, 2, 9, 15, 8]: + raise UserError("Hanya Finance yang bisa ubah Draft") + res = super(AccountMove, self).button_draft() + return res + + def button_cancel(self): + if self.env.user.id not in [24, 13, 10, 2, 9, 15, 8]: + raise UserError('Hanya Accounting yang bisa Cancel') + res = super(AccountMove, self).button_cancel() + + return res def _compute_need_refund(self): for move in self: @@ -223,6 +258,8 @@ class AccountMove(models.Model): } def action_post(self): + if self.env.user.id not in [24, 13, 10, 2, 9, 15, 8]: + raise UserError('Hanya Accounting yang bisa Post') res = super(AccountMove, self).action_post() for entry in self: if entry.move_type == 'out_invoice': diff --git a/fixco_custom/models/account_move_reversal.py b/fixco_custom/models/account_move_reversal.py index eac8660..2645645 100644 --- a/fixco_custom/models/account_move_reversal.py +++ b/fixco_custom/models/account_move_reversal.py @@ -11,8 +11,13 @@ class AccountMoveReversal(models.TransientModel): self.ensure_one() moves = self.move_ids - if moves.move_type == 'entry' and moves.sale_id and moves.ref.startswith('UANG MUKA PENJUALAN') and self.env.user.id not in [9, 10, 15]: - raise UserError(_('Anda tidak memiliki akses untuk melakukan reverse Uang Muka Penjualan!')) + if moves.move_type == 'entry' and moves.sale_id and moves.ref.startswith('UANG MUKA PENJUALAN'): + if not moves.approval_refund: + raise UserError(_('User harus ajukan approval refund!')) + if moves.approval_refund == 'rejected': + raise UserError(_('refund telah ditolak!')) + + moves.approval_refund = 'approved' # Create default values. default_values_list = [] diff --git a/fixco_custom/models/account_payment.py b/fixco_custom/models/account_payment.py new file mode 100644 index 0000000..2c7a5b4 --- /dev/null +++ b/fixco_custom/models/account_payment.py @@ -0,0 +1,11 @@ +from odoo import fields, models, api +from odoo.tools.misc import format_date, OrderedSet +from odoo.exceptions import UserError + +class AccountPayment(models.Model): + _inherit = 'account.payment' + + @api.constrains('journal_id') + def set_default_journal_id(self): + for rec in self: + rec.journal_id = 21 \ No newline at end of file diff --git a/fixco_custom/models/detail_order.py b/fixco_custom/models/detail_order.py index b3e10a2..c256d8c 100755 --- a/fixco_custom/models/detail_order.py +++ b/fixco_custom/models/detail_order.py @@ -5,9 +5,10 @@ import requests import json import hmac import base64 -from datetime import datetime, timezone +from datetime import datetime, timezone, timedelta from hashlib import sha256 import logging +import pytz _logger = logging.getLogger(__name__) @@ -205,6 +206,21 @@ class DetailOrder(models.Model): return partner.id def prepare_data_so(self, json_data): + date_str = json_data.get('data', [{}])[0].get('promisedToShipBefore') + deadline_date = False + + if date_str: + # utc_dt = datetime.strptime( + # date_str, + # "%Y-%m-%dT%H:%M:%SZ" + # ).replace(tzinfo=pytz.UTC) + + # wib_tz = pytz.timezone('Asia/Jakarta') + # deadline_date = utc_dt.astimezone(wib_tz).replace(tzinfo=None) + deadline_date = datetime.strptime( + date_str, + "%Y-%m-%dT%H:%M:%SZ" + ) + timedelta(hours=1) data = { 'partner_id': self.get_partner(json_data.get('data', {})[0].get('shopId')), 'client_order_ref': json_data.get('data', {})[0].get('orderId'), @@ -214,6 +230,7 @@ class DetailOrder(models.Model): 'invoice_mp': json_data.get('data', {})[0].get('externalOrderId'), 'source': 'ginee', 'channel': json_data.get('data', {})[0].get('channel'), + 'deadline_date': deadline_date, } return data diff --git a/fixco_custom/models/sale.py b/fixco_custom/models/sale.py index cd5f68f..b8aa963 100755 --- a/fixco_custom/models/sale.py +++ b/fixco_custom/models/sale.py @@ -19,6 +19,8 @@ class SaleOrder(models.Model): remaining_down_payment = fields.Float('Remaining Down Payment', compute='_compute_remaining_down_payment', store=True) + deadline_date = fields.Datetime('Deadline', copy=False) + def create_invoices(self): created_invoices = self.env['account.move'] for order in self: diff --git a/fixco_custom/models/stock_picking.py b/fixco_custom/models/stock_picking.py index 76c2ecf..c2d5150 100755 --- a/fixco_custom/models/stock_picking.py +++ b/fixco_custom/models/stock_picking.py @@ -68,6 +68,29 @@ class StockPicking(models.Model): list_product = fields.Char(string='List Product') is_dispatched = fields.Boolean(string='Is Dispatched', default=False, compute='_compute_is_dispatched', readonly=True) + def check_qty_bundling_product(self): + for line in self.move_ids_without_package: + if '(Bundle Component)' in line.sale_line_id.name: + if line.forecast_availability < 1 or line.quantity_done < 1: + raise UserError('Barang Bundling : %s Quantity Done tidak boleh 0' % line.product_id.display_name) + + def check_qty_done_stock(self): + for line in self.move_line_ids_without_package: + def check_qty_per_inventory(self, product, location): + quant = self.env['stock.quant'].search([ + ('product_id', '=', product.id), + ('location_id', '=', location.id), + ]) + + if quant: + return quant.quantity + + return 0 + + qty_onhand = check_qty_per_inventory(self, line.product_id, line.location_id) + if line.qty_done > qty_onhand: + raise UserError('Quantity Done melebihi Quantity Onhand') + @api.depends('shipment_group_id') def _compute_is_dispatched(self): for picking in self: @@ -122,6 +145,10 @@ class StockPicking(models.Model): return action def button_validate(self): + if not self.picking_type_code == 'incoming' and not self.name.startswith('BU/IN'): + self.check_qty_done_stock() + self.check_qty_bundling_product() + origin = self.origin or '' if any(prefix in origin for prefix in ['PO/', 'SO/']) and not self.check_product_lines and not self.name.startswith('BU/INT'): raise UserError(_("Belum ada check product, gabisa validate")) @@ -285,6 +312,7 @@ class StockPicking(models.Model): self.carrier = picking.sale_id.carrier self.address = picking.sale_id.address self.note_by_buyer = picking.sale_id.note_by_buyer + self.date_deadline = picking.sale_id.deadline_date self.schema_multi_single_sku() def schema_multi_single_sku(self): diff --git a/fixco_custom/views/account_move.xml b/fixco_custom/views/account_move.xml index 52dd64c..d5ae9ae 100644 --- a/fixco_custom/views/account_move.xml +++ b/fixco_custom/views/account_move.xml @@ -10,6 +10,28 @@