change employee_custody_request
This commit is contained in:
parent
2961cd55b2
commit
1d0b12d841
|
|
@ -20,7 +20,7 @@ This course provides a comprehensive, hands-on guide to managing employee custod
|
|||
'version': '0.1',
|
||||
|
||||
# any module necessary for this one to work correctly
|
||||
'depends': ['base','hr','account','exp_payroll_custom','hr_expense','odex25_account_reports','system_dashboard_classic','exp_budget_check'],
|
||||
'depends': ['base','hr','account','exp_payroll_custom','hr_expense','odex25_account_reports','system_dashboard_classic'],
|
||||
|
||||
# always loaded
|
||||
'data': [
|
||||
|
|
@ -33,11 +33,9 @@ This course provides a comprehensive, hands-on guide to managing employee custod
|
|||
'views/account_journal.xml',
|
||||
'views/types_custody.xml',
|
||||
'wizard/account_paymrnt_register_views.xml',
|
||||
'wizard/hr_request_pledge_confirm_wizard_view.xml',
|
||||
'views/hr_expenes.xml'
|
||||
|
||||
],
|
||||
# only loaded in demonstration mode
|
||||
'demo': [
|
||||
'demo/demo.xml',
|
||||
],
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,7 +191,8 @@ msgstr ""
|
|||
#. module: employee_custody_request
|
||||
#: model_terms:ir.ui.view,arch_db:employee_custody_request.job_request_form_pledge_view
|
||||
msgid "GM Manager Approve"
|
||||
msgstr "تصديق المدير العام"
|
||||
msgstr "تصديق الموارد البشرية"
|
||||
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: model:ir.actions.server,name:employee_custody_request.action_report_partner_ledger_inherited_test
|
||||
|
|
@ -280,8 +281,9 @@ msgstr ""
|
|||
#. module: employee_custody_request
|
||||
#: model:ir.model.fields,field_description:employee_custody_request.field_hr_employee__journal_id
|
||||
#: model:ir.model.fields,field_description:employee_custody_request.field_hr_request_pledge__journal_id
|
||||
#: model:ir.model.fields,field_description:employee_custody_request.field_hr_expense_sheet__custody_bank_journal_id
|
||||
msgid "Journal"
|
||||
msgstr "دفاتر اليومية"
|
||||
msgstr "دفتر اليومية"
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: model_terms:ir.ui.view,arch_db:employee_custody_request.view_employee_journal_form_inherit
|
||||
|
|
@ -405,6 +407,16 @@ msgstr "الدفعات"
|
|||
msgid "Payroll Officer Approve"
|
||||
msgstr "تصديق مسؤول الرواتب"
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: model_terms:ir.ui.view,arch_db:employee_custody_request.job_request_form_pledge_view
|
||||
msgid "Feed Pledge"
|
||||
msgstr "تغذية العهدة"
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: model_terms:ir.ui.view,arch_db:employee_custody_request.job_request_form_pledge_view
|
||||
msgid "Close Pledge"
|
||||
msgstr "إقفال العهدة"
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: code:addons/employee_custody_request/models/models.py:0
|
||||
#, python-format
|
||||
|
|
@ -548,6 +560,13 @@ msgstr "إنتظار الموارد البشرية"
|
|||
msgid "Wait Transfer"
|
||||
msgstr "إنتظار الترحيل"
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: code:addons/employee_custody_request/models/models.py:0
|
||||
#: model:ir.model.fields.selection,name:employee_custody_request.selection__hr_request_pledge__state__locked
|
||||
#, python-format
|
||||
msgid "Locked"
|
||||
msgstr "مغلقة"
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: code:addons/employee_custody_request/models/models.py:0
|
||||
#: model:ir.model.fields.selection,name:employee_custody_request.selection__hr_request_pledge__state__submit
|
||||
|
|
@ -597,6 +616,7 @@ msgstr "دفتر عهد"
|
|||
msgid "Custody Partner"
|
||||
msgstr "شريك العهده"
|
||||
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: code:addons/odoo/odex25-ensan-project/employee_custody_request/models/models.py:0
|
||||
#: code:addons/employee_custody_request/models/models.py:0
|
||||
|
|
@ -607,6 +627,7 @@ msgstr "يجب أن يكون لدى الموظف شريك ذو صلة."
|
|||
|
||||
#. module: employee_custody_request
|
||||
#: model:ir.model.fields,field_description:employee_custody_request.field_account_journal__partner_id
|
||||
#: model:ir.model.fields,field_description:employee_custody_request.field_hr_expense_sheet__custody_partner_id
|
||||
msgid "Partner"
|
||||
msgstr "الشريك"
|
||||
|
||||
|
|
@ -707,3 +728,115 @@ msgstr "عند اختيار نوع الدفع 'عهدة'، يجب تحديد ش
|
|||
#: model:ir.model.fields.selection,name:employee_custody_request.selection__hr_expense__payment_mode__custody
|
||||
msgid "Custody"
|
||||
msgstr "عهده"
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: model:ir.model.fields,field_description:employee_custody_request.field_custody_types__company_id
|
||||
#: model:ir.model.fields,field_description:employee_custody_request.field_hr_request_pledge__company_id
|
||||
#: model:ir.model.fields.selection,name:employee_custody_request.selection__hr_expense__payment_mode__company_account
|
||||
msgid "Company"
|
||||
msgstr "المؤسسة"
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: model:ir.model.fields,field_description:employee_custody_request.field_hr_request_pledge__permanent_pledge
|
||||
msgid "Permanent Pledge"
|
||||
msgstr "عهدة مستديمة"
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: model:ir.model.fields,field_description:employee_custody_request.field_hr_request_pledge__total_refunded_amount
|
||||
msgid "Total Refunded Amount"
|
||||
msgstr "إجمالي قيمة المبالغ المرتجعة"
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: model:ir.model.fields,field_description:employee_custody_request.field_hr_request_pledge__total_paid_amount
|
||||
msgid "Total Paid Amount"
|
||||
msgstr "اجمالي المدفوعات"
|
||||
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: code:addons/employee_custody_request/models/models.py:0
|
||||
#: code:addons/odoo/preprod_master/odex25_accounting/employee_custody_request/models/models.py:0
|
||||
#, python-format
|
||||
msgid "Cannot create a new payment: the last payment for this pledge is less than 1 year old."
|
||||
msgstr "لا يمكن إنشاء دفعة جديدة: آخر دفعة لهذه العهدة لم يمر عليها عام كامل."
|
||||
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: model:ir.model.fields,field_description:employee_custody_request.field_account_payment__petty_cash_pledge
|
||||
#: model:ir.model.fields.selection,name:employee_custody_request.selection__hr_expense__payment_mode__petty_cash
|
||||
msgid "Petty Cash"
|
||||
msgstr "عهدة موظف"
|
||||
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: model:ir.model.fields,field_description:employee_custody_request.field_account_payment__original_move_id
|
||||
msgid "Reference"
|
||||
msgstr "المرجع"
|
||||
|
||||
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: code:addons/employee_custody_request/models/models.py:0
|
||||
#: code:addons/odoo/preprod_master/odex25_accounting/employee_custody_request/models/models.py:0
|
||||
#, python-format
|
||||
msgid "✅ A new pledge has been successfully created with an amount of %.2f."
|
||||
msgstr "✅ تم إنشاء عهدة جديدة بنجاح بمبلغ %.2f."
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: code:addons/employee_custody_request/models/models.py:0
|
||||
#: code:addons/odoo/preprod_master/odex25_accounting/employee_custody_request/models/models.py:0
|
||||
#, python-format
|
||||
msgid "✅ The pledge has been successfully funded with an amount of %.2f."
|
||||
msgstr "✅ تم تغذية العهدة بنجاح بمبلغ %.2f."
|
||||
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: code:addons/employee_custody_request/models/models.py:0
|
||||
#: code:addons/odoo/preprod_master/odex25_accounting/employee_custody_request/models/models.py:0
|
||||
#, python-format
|
||||
msgid "Operation Successful"
|
||||
msgstr "تمت العملية بنجاح"
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: code:addons/employee_custody_request/models/hr_expense.py:0
|
||||
#: code:addons/employee_custody_request/models/hr_expense_sheet.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The employee %s has no available custody balance to cover this expense "
|
||||
"sheet."
|
||||
msgstr "الموظف %s لا يمتلك رصيد عهده متاح لتغطية تقرير المصروف هذا."
|
||||
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: model_terms:ir.ui.view,arch_db:employee_custody_request.view_hr_request_pledge_confirm_wizard_form
|
||||
msgid "Are you sure you want to feed the pledge?"
|
||||
msgstr "هل أنت متأكد أنك تريد تغذية العهدة؟"
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: model_terms:ir.ui.view,arch_db:employee_custody_request.view_hr_request_pledge_confirm_wizard_form
|
||||
msgid "Confirm"
|
||||
msgstr "تأكيد"
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: model_terms:ir.ui.view,arch_db:employee_custody_request.view_hr_request_pledge_confirm_wizard_form
|
||||
msgid "Cancel"
|
||||
msgstr "إلغاء"
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: code:addons/employee_custody_request/models/models.py:0
|
||||
#: model:ir.model,name:employee_custody_request.model_hr_request_pledge_confirm_wizard
|
||||
#, python-format
|
||||
msgid "Confirmation Wizard for Pledge Payment"
|
||||
msgstr "التأكيد لدفع العهدة"
|
||||
|
||||
|
||||
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: model_terms:ir.ui.view,arch_db:employee_custody_request.job_request_form_pledge_view
|
||||
msgid "Refund"
|
||||
msgstr "ارجاع"
|
||||
|
||||
#. module: employee_custody_request
|
||||
#: model_terms:ir.ui.view,arch_db:employee_custody_request.job_request_form_pledge_view
|
||||
msgid "Show Refunds"
|
||||
msgstr "حساب الارجاع"
|
||||
|
|
|
|||
|
|
@ -17,23 +17,3 @@ class AccountJournalInherit(models.Model):
|
|||
help='Partner associated with this journal'
|
||||
)
|
||||
|
||||
|
||||
@api.onchange('custody_journal')
|
||||
def _onchange_custody_journal(self):
|
||||
if not self.custody_journal:
|
||||
return {
|
||||
'domain': {'default_account_id': []}
|
||||
}
|
||||
else:
|
||||
return {
|
||||
'domain': {
|
||||
'default_account_id': [('user_type_id.type', '=', 'receivable')]
|
||||
}
|
||||
}
|
||||
|
||||
@api.constrains('custody_journal', 'default_account_id')
|
||||
def _check_custody_account_type(self):
|
||||
for record in self:
|
||||
if record.custody_journal and record.default_account_id:
|
||||
if record.default_account_id.user_type_id.type != 'receivable':
|
||||
raise ValidationError(_('You must select an account of type "Debit" for the Advances Ledger'))
|
||||
|
|
@ -1,9 +1,43 @@
|
|||
from odoo import models, _ ,api
|
||||
from odoo import models, _ ,api,fields
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class AccountPayment(models.Model):
|
||||
_inherit = "account.payment"
|
||||
|
||||
petty_cash_pledge = fields.Boolean(
|
||||
string="Petty Cash",
|
||||
default=False,
|
||||
)
|
||||
hr_request_pledge = fields.Many2one('hr.request.pledge')
|
||||
hr_request_pledge_id = fields.Many2one(
|
||||
'hr.request.pledge',
|
||||
string="Pledge",
|
||||
ondelete="cascade"
|
||||
)
|
||||
skip_paired_payment = fields.Boolean(
|
||||
string="تجاوز إنشاء الدفعة المقابلة",
|
||||
default=False,
|
||||
)
|
||||
original_move_id = fields.Many2one('account.move', string="Reference")
|
||||
|
||||
|
||||
|
||||
def action_go_to_hr_request_pledge(self):
|
||||
pledge_record = self.env['hr.request.pledge'].search(
|
||||
[('id', '=', self.hr_request_pledge_id.id)],
|
||||
limit=1
|
||||
)
|
||||
if pledge_record:
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': 'HR Request Pledge',
|
||||
'res_model': 'hr.request.pledge',
|
||||
'res_id': pledge_record.id,
|
||||
'view_mode': 'form',
|
||||
'view_type': 'form',
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
def _synchronize_from_moves(self, changed_fields):
|
||||
''' Update the account.payment regarding its related account.move.
|
||||
|
|
@ -30,16 +64,26 @@ class AccountPayment(models.Model):
|
|||
|
||||
if 'line_ids' in changed_fields:
|
||||
all_lines = move.line_ids
|
||||
|
||||
liquidity_lines, counterpart_lines, writeoff_lines = pay._seek_for_lines()
|
||||
|
||||
if len(liquidity_lines) != 1 or len(counterpart_lines) != 1:
|
||||
raise UserError(_(
|
||||
"The journal entry %s reached an invalid state relative to its payment.\n"
|
||||
"To be consistent, the journal entry must always contains:\n"
|
||||
"- one journal item involving the outstanding payment/receipts account.\n"
|
||||
"- one journal item involving a receivable/payable account.\n"
|
||||
"- optional journal items, all sharing the same account.\n\n"
|
||||
) % move.display_name)
|
||||
if not (
|
||||
self.move_id
|
||||
and self.move_id.line_ids
|
||||
and self.hr_request_pledge_id
|
||||
and self.is_internal_transfer
|
||||
):
|
||||
raise UserError(_(
|
||||
"The journal entry %s reached an invalid state relative to its payment.\n"
|
||||
"To be consistent, the journal entry must always contain:\n"
|
||||
"- one journal item involving the outstanding payment/receipts account.\n"
|
||||
"- one journal item involving a receivable/payable account.\n"
|
||||
"- optional journal items, all sharing the same account.\n\n"
|
||||
) % move.display_name)
|
||||
|
||||
|
||||
|
||||
|
||||
if writeoff_lines and len(writeoff_lines.account_id) != 1:
|
||||
raise UserError(_(
|
||||
|
|
@ -84,12 +128,18 @@ class AccountPayment(models.Model):
|
|||
'currency_id': liquidity_lines.currency_id.id,
|
||||
'partner_id': liquidity_lines.partner_id.id,
|
||||
})
|
||||
payment_vals_to_write.update({
|
||||
'amount': abs(liquidity_amount),
|
||||
'currency_id': liquidity_lines.currency_id.id,
|
||||
'destination_account_id': counterpart_lines.account_id.id,
|
||||
'partner_id': liquidity_lines.partner_id.id,
|
||||
})
|
||||
if not (
|
||||
self.move_id
|
||||
and self.move_id.line_ids
|
||||
and self.hr_request_pledge_id
|
||||
and self.is_internal_transfer
|
||||
):
|
||||
payment_vals_to_write.update({
|
||||
'amount': abs(liquidity_amount),
|
||||
'currency_id': liquidity_lines.currency_id.id,
|
||||
'destination_account_id': counterpart_lines.account_id.id,
|
||||
'partner_id': liquidity_lines.partner_id.id,
|
||||
})
|
||||
if liquidity_amount > 0.0:
|
||||
payment_vals_to_write.update({'payment_type': 'inbound'})
|
||||
elif liquidity_amount < 0.0:
|
||||
|
|
@ -107,27 +157,47 @@ class AccountPayment(models.Model):
|
|||
is_account_ok = payment.destination_account_id and payment.destination_account_id == payment.journal_id.company_id.transfer_account_id
|
||||
payment.is_internal_transfer = is_partner_ok and is_account_ok
|
||||
|
||||
|
||||
|
||||
|
||||
def action_post(self):
|
||||
res = super().action_post()
|
||||
@api.depends('partner_id', 'destination_account_id', 'journal_id', 'skip_paired_payment')
|
||||
def _compute_is_internal_transfer(self):
|
||||
super(AccountPayment, self)._compute_is_internal_transfer()
|
||||
|
||||
for payment in self:
|
||||
if not self.hr_request_pledge:
|
||||
if payment.skip_paired_payment:
|
||||
payment.is_internal_transfer = True
|
||||
|
||||
if payment.journal_id.custody_journal and payment.partner_id:
|
||||
employee = self.env['hr.employee'].sudo().search([
|
||||
('user_id.partner_id', '=', payment.partner_id.id)
|
||||
], limit=1)
|
||||
print("pledge")
|
||||
if employee:
|
||||
self.env['hr.request.pledge'].allocate_payment_to_pledges(
|
||||
employee_id=employee.id,
|
||||
journal_id=payment.journal_id.id,
|
||||
amount=payment.amount
|
||||
)
|
||||
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
payment = super(AccountPayment, self).create(vals)
|
||||
ref = payment.payment_reference
|
||||
move = self.env['account.move'].search([('name', '=like', f"{ref}%")], limit=1)
|
||||
if move:
|
||||
payment.original_move_id = move.id
|
||||
if move.move_type in ['in_invoice', 'in_receipt'] and move.is_petty_paid:
|
||||
payment.petty_cash_pledge = True
|
||||
return payment
|
||||
|
||||
def action_draft_accountant(self):
|
||||
for rec in self:
|
||||
print(self.move_id.line_ids)
|
||||
print(self.destination_journal_id)
|
||||
|
||||
if self.move_id and self.move_id.line_ids and self.hr_request_pledge_id and self.is_internal_transfer:
|
||||
for line in self.move_id.line_ids:
|
||||
if line.debit > 0.0:
|
||||
line.write({
|
||||
'account_id': self.destination_journal_id.payment_debit_account_id.id
|
||||
})
|
||||
line.move_id._recompute_dynamic_lines()
|
||||
|
||||
if rec.petty_cash_pledge and rec.payment_reference:
|
||||
rec.action_post()
|
||||
rec.set_posted_state()
|
||||
else:
|
||||
print("its hr_request_pledge")
|
||||
super(AccountPayment, rec).action_draft_accountant()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
return res
|
||||
|
|
|
|||
|
|
@ -6,13 +6,45 @@ from odoo.tools import float_compare, float_is_zero
|
|||
|
||||
class HrExpense(models.Model):
|
||||
_inherit = 'hr.expense'
|
||||
#
|
||||
# payment_mode = fields.Selection(
|
||||
# selection_add=[
|
||||
# ("custody", "Custody")
|
||||
# ]
|
||||
# )
|
||||
payment_mode = fields.Selection([
|
||||
("own_account", "Employee (to reimburse)"),
|
||||
("company_account", "Company"),
|
||||
("custody", "Custody"),
|
||||
("petty_cash", "Petty Cash")
|
||||
], default='custody', tracking=True, states={'done': [('readonly', True)], 'approved': [('readonly', True)], 'reported': [('readonly', True)]}, string="Paid By")
|
||||
|
||||
payment_mode = fields.Selection(
|
||||
selection_add=[
|
||||
("custody", "Custody")
|
||||
]
|
||||
)
|
||||
|
||||
def action_submit_expenses(self):
|
||||
for sheet in self:
|
||||
if sheet.payment_mode == 'custody':
|
||||
employee = sheet.employee_id
|
||||
available_pledges = self.env['hr.request.pledge'].sudo().search([
|
||||
('employee_id', '=', employee.id),
|
||||
('custody_status', 'in', ['partial', 'new']),
|
||||
])
|
||||
available_pledges = available_pledges.filtered(
|
||||
lambda p: p.custody_status in ['partial', 'new'] and p.state == 'pay'
|
||||
)
|
||||
|
||||
if not available_pledges:
|
||||
raise UserError(
|
||||
_("The employee %s has no available custody balance to cover this expense sheet.") % employee.name
|
||||
)
|
||||
return super().action_submit_expenses()
|
||||
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
|
||||
res = super(HrExpense, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
|
||||
if view_type in ['form', 'tree']:
|
||||
if 'fields' in res and 'payment_mode' in res['fields']:
|
||||
selection = res['fields']['payment_mode']['selection']
|
||||
# احذف petty_cash من الواجهة
|
||||
res['fields']['payment_mode']['selection'] = [s for s in selection if s[0] != 'petty_cash']
|
||||
return res
|
||||
def _create_sheet_from_expense_custody(self):
|
||||
"""Create expense sheet for custody mode"""
|
||||
if any(expense.state != "draft" or expense.sheet_id for expense in self):
|
||||
|
|
@ -32,16 +64,16 @@ class HrExpense(models.Model):
|
|||
return sheet
|
||||
|
||||
def _create_sheet_from_expenses(self):
|
||||
payment_mode = set(self.mapped("payment_mode"))
|
||||
if len(payment_mode) > 1 and "petty_cash" in payment_mode:
|
||||
raise UserError(
|
||||
_("You cannot create report from many petty cash mode and other.")
|
||||
)
|
||||
if all(expense.payment_mode == "petty_cash" for expense in self):
|
||||
return self._create_sheet_from_expense_petty_cash()
|
||||
if all(expense.payment_mode == "custody" for expense in self):
|
||||
return self._create_sheet_from_expense_custody()
|
||||
return super()._create_sheet_from_expenses()
|
||||
# payment_mode = set(self.mapped("payment_mode"))
|
||||
# if len(payment_mode) > 1 and "petty_cash" in payment_mode:
|
||||
# raise UserError(
|
||||
# _("You cannot create report from many petty cash mode and other.")
|
||||
# )
|
||||
# if all(expense.payment_mode == "petty_cash" for expense in self):
|
||||
# return self._create_sheet_from_expense_petty_cash()
|
||||
# if all(expense.payment_mode == "custody" for expense in self):
|
||||
# return self._create_sheet_from_expense_custody()
|
||||
return self._create_sheet_from_expense_custody()
|
||||
|
||||
def _get_expense_account_destination(self):
|
||||
self.ensure_one()
|
||||
|
|
@ -57,14 +89,23 @@ class HrExpense(models.Model):
|
|||
account_dest = self.sheet_id.bank_journal_id.payment_credit_account_id.id
|
||||
|
||||
elif self.payment_mode == 'custody':
|
||||
if self.sheet_id.account_payment_method_id:
|
||||
account_dest = self.sheet_id.account_payment_method_id.payment_account_id.id
|
||||
else:
|
||||
if not self.sheet_id.custody_bank_journal_id.payment_credit_account_id:
|
||||
raise UserError(
|
||||
_("No Outstanding Payments Account found for the %s journal, please configure one.") % (
|
||||
self.sheet_id.custody_bank_journal_id.name))
|
||||
account_dest = self.sheet_id.custody_bank_journal_id.payment_credit_account_id.id
|
||||
partner = self.sheet_id.custody_partner_id
|
||||
if not partner:
|
||||
raise UserError(_("Please set a Custody Partner before proceeding."))
|
||||
|
||||
if not partner.property_account_payable_id:
|
||||
raise UserError(_("The Custody Partner %s has no payable account configured.") % partner.name)
|
||||
|
||||
account_dest = partner.property_account_payable_id.id
|
||||
# elif self.payment_mode == 'custody':
|
||||
# if self.sheet_id.account_payment_method_id:
|
||||
# account_dest = self.sheet_id.account_payment_method_id.payment_account_id.id
|
||||
# else:
|
||||
# if not self.sheet_id.custody_bank_journal_id.payment_credit_account_id:
|
||||
# raise UserError(
|
||||
# _("No Outstanding Payments Account found for the %s journal, please configure one.") % (
|
||||
# self.sheet_id.custody_bank_journal_id.name))
|
||||
# account_dest = self.sheet_id.custody_bank_journal_id.payment_credit_account_id.id
|
||||
|
||||
else:
|
||||
return super(HrExpense, self)._get_expense_account_destination()
|
||||
|
|
@ -74,13 +115,13 @@ class HrExpense(models.Model):
|
|||
def _prepare_move_values(self):
|
||||
"""Override to handle custody payment mode like company_account"""
|
||||
self.ensure_one()
|
||||
|
||||
if self.payment_mode == 'company_account':
|
||||
journal = self.sheet_id.bank_journal_id
|
||||
elif self.payment_mode == 'custody':
|
||||
journal = self.sheet_id.custody_bank_journal_id or self.sheet_id.bank_journal_id
|
||||
else:
|
||||
journal = self.sheet_id.journal_id
|
||||
journal = self.sheet_id.custody_bank_journal_id or self.sheet_id.bank_journal_id
|
||||
# if self.payment_mode == 'company_account':
|
||||
# journal = self.sheet_id.bank_journal_id
|
||||
# elif self.payment_mode == 'custody':
|
||||
# journal = self.sheet_id.custody_bank_journal_id or self.sheet_id.bank_journal_id
|
||||
# else:
|
||||
# journal = self.sheet_id.journal_id
|
||||
|
||||
account_date = self.sheet_id.accounting_date or self.date
|
||||
move_values = {
|
||||
|
|
@ -89,38 +130,165 @@ class HrExpense(models.Model):
|
|||
'date': account_date,
|
||||
'ref': self.sheet_id.name,
|
||||
'name': '/',
|
||||
'move_type' :'in_receipt',
|
||||
'invoice_date': self.date,
|
||||
'partner_id': self.sheet_id.custody_partner_id.id
|
||||
|
||||
|
||||
}
|
||||
if self.payment_mode == 'custody':
|
||||
move_values['is_petty_paid'] = True
|
||||
move_values['petty_employee_id'] = self.sheet_id.employee_id.id
|
||||
return move_values
|
||||
|
||||
def action_move_create(self):
|
||||
move_group_by_sheet = super().action_move_create()
|
||||
|
||||
def send_attachments_to_move(self):
|
||||
expense_attachments = self.env['ir.attachment'].search([
|
||||
('res_model', '=', 'hr.expense'),
|
||||
('res_id', 'in', self.ids)
|
||||
])
|
||||
sheet_attachments = self.env['ir.attachment'].search([
|
||||
('res_model', '=', 'hr.expense.sheet'),
|
||||
('res_id', 'in', self.mapped('sheet_id').ids)
|
||||
])
|
||||
for expense in self:
|
||||
if expense.payment_mode == 'custody':
|
||||
move = expense.sheet_id.account_move_id
|
||||
partner_id = expense.sheet_id.custody_partner_id.id if expense.sheet_id.custody_partner_id else \
|
||||
expense.employee_id.sudo().address_home_id.commercial_partner_id.id
|
||||
amount =0
|
||||
for line in move.line_ids:
|
||||
if line.credit > 0:
|
||||
amount += line.credit
|
||||
line.write({'partner_id': partner_id})
|
||||
if move.state == 'posted':
|
||||
print("amount",amount)
|
||||
employee = self.env['hr.employee'].sudo().search([
|
||||
('user_id.partner_id', '=', partner_id)
|
||||
], limit=1)
|
||||
move = expense.sheet_id.account_move_id
|
||||
for att in expense_attachments + sheet_attachments:
|
||||
att.copy({'res_model': 'account.move', 'res_id': move.id})
|
||||
|
||||
if employee:
|
||||
def action_move_create(self):
|
||||
expenses = self.filtered(lambda x: not x.is_refused)
|
||||
if not expenses:
|
||||
return {}
|
||||
|
||||
self.env['hr.request.pledge'].allocate_payment_to_pledges(
|
||||
employee_id=employee.id,
|
||||
journal_id=move.journal_id.id,
|
||||
amount=amount
|
||||
)
|
||||
move_group_by_sheet = expenses._get_account_move_by_sheet()
|
||||
move_line_values_by_expense = expenses._get_account_move_line_values()
|
||||
|
||||
print(f"✅ posted {move.name} expense {expense.name}")
|
||||
else:
|
||||
print(f"❌ not posted {expense.name}")
|
||||
for expense in expenses:
|
||||
move = move_group_by_sheet[expense.sheet_id.id]
|
||||
move_line_values = move_line_values_by_expense.get(expense.id)
|
||||
|
||||
move.write({'line_ids': [(0, 0, line) for line in move_line_values]})
|
||||
expense.sheet_id.write({'account_move_id': move.id})
|
||||
|
||||
if expense.payment_mode == 'company_account':
|
||||
expense.sheet_id.paid_expense_sheets()
|
||||
|
||||
for expense in expenses:
|
||||
move = move_group_by_sheet[expense.sheet_id.id]
|
||||
|
||||
# if expense.payment_mode == 'custody':
|
||||
# if move.state != 'posted':
|
||||
# move.action_budget_management()
|
||||
|
||||
partner_id = (
|
||||
expense.sheet_id.custody_partner_id.id
|
||||
if expense.sheet_id.custody_partner_id
|
||||
else expense.employee_id.sudo().address_home_id.commercial_partner_id.id
|
||||
)
|
||||
|
||||
amount = 0
|
||||
for line in move.line_ids:
|
||||
if line.debit > 0:
|
||||
amount += line.debit
|
||||
line.write({'partner_id': partner_id})
|
||||
|
||||
# else:
|
||||
# if move.state != 'posted':
|
||||
# move._post()
|
||||
self.send_attachments_to_move()
|
||||
return move_group_by_sheet
|
||||
|
||||
|
||||
|
||||
def _get_account_move_line_values(self):
|
||||
move_line_values_by_expense = {}
|
||||
for expense in self:
|
||||
move_line_name = expense.employee_id.name + ': ' + expense.name.split('\n')[0][:64]
|
||||
account_src = expense._get_expense_account_source()
|
||||
account_dst = expense._get_expense_account_destination()
|
||||
account_date = expense.date or expense.sheet_id.accounting_date or fields.Date.context_today(expense)
|
||||
|
||||
company_currency = expense.company_id.currency_id
|
||||
|
||||
move_line_values = []
|
||||
taxes = expense.tax_ids.with_context(round=True).compute_all(expense.unit_amount, expense.currency_id, expense.quantity, expense.product_id)
|
||||
total_amount = 0.0
|
||||
total_amount_currency = 0.0
|
||||
partner_id = expense.employee_id.sudo().address_home_id.commercial_partner_id.id
|
||||
|
||||
# source move line
|
||||
balance = expense.currency_id._convert(taxes['total_excluded'], company_currency, expense.company_id, account_date)
|
||||
amount_currency = taxes['total_excluded']
|
||||
move_line_src = {
|
||||
'name': move_line_name,
|
||||
'quantity': expense.quantity or 1,
|
||||
'debit': balance if balance > 0 else 0,
|
||||
'credit': -balance if balance < 0 else 0,
|
||||
'amount_currency': amount_currency,
|
||||
'account_id': account_src.id,
|
||||
'product_id': expense.product_id.id,
|
||||
'product_uom_id': expense.product_uom_id.id,
|
||||
'analytic_account_id': expense.analytic_account_id.id,
|
||||
'analytic_tag_ids': [(6, 0, expense.analytic_tag_ids.ids)],
|
||||
'expense_id': expense.id,
|
||||
'partner_id': partner_id,
|
||||
'tax_ids': [(6, 0, expense.tax_ids.ids)],
|
||||
'tax_tag_ids': [(6, 0, taxes['base_tags'])],
|
||||
'currency_id': expense.currency_id.id,
|
||||
}
|
||||
move_line_values.append(move_line_src)
|
||||
total_amount -= balance
|
||||
total_amount_currency -= move_line_src['amount_currency']
|
||||
|
||||
# taxes move lines
|
||||
for tax in taxes['taxes']:
|
||||
balance = expense.currency_id._convert(tax['amount'], company_currency, expense.company_id, account_date)
|
||||
amount_currency = tax['amount']
|
||||
|
||||
if tax['tax_repartition_line_id']:
|
||||
rep_ln = self.env['account.tax.repartition.line'].browse(tax['tax_repartition_line_id'])
|
||||
base_amount = self.env['account.move']._get_base_amount_to_display(tax['base'], rep_ln)
|
||||
base_amount = expense.currency_id._convert(base_amount, company_currency, expense.company_id, account_date)
|
||||
else:
|
||||
base_amount = None
|
||||
|
||||
move_line_tax_values = {
|
||||
'name': tax['name'],
|
||||
'quantity': 1,
|
||||
'debit': balance if balance > 0 else 0,
|
||||
'credit': -balance if balance < 0 else 0,
|
||||
'amount_currency': amount_currency,
|
||||
'account_id': tax['account_id'] or move_line_src['account_id'],
|
||||
'tax_repartition_line_id': tax['tax_repartition_line_id'],
|
||||
'tax_tag_ids': tax['tag_ids'],
|
||||
'tax_base_amount': base_amount,
|
||||
'expense_id': expense.id,
|
||||
'partner_id': partner_id,
|
||||
'currency_id': expense.currency_id.id,
|
||||
'analytic_account_id': expense.analytic_account_id.id if tax['analytic'] else False,
|
||||
'analytic_tag_ids': [(6, 0, expense.analytic_tag_ids.ids)] if tax['analytic'] else False,
|
||||
}
|
||||
total_amount -= balance
|
||||
total_amount_currency -= move_line_tax_values['amount_currency']
|
||||
move_line_values.append(move_line_tax_values)
|
||||
|
||||
# destination move line
|
||||
move_line_dst = {
|
||||
'name': move_line_name,
|
||||
'debit': total_amount > 0 and total_amount,
|
||||
'credit': total_amount < 0 and -total_amount,
|
||||
'account_id': account_dst,
|
||||
'date_maturity': account_date,
|
||||
'amount_currency': total_amount_currency,
|
||||
'currency_id': expense.currency_id.id,
|
||||
'expense_id': expense.id,
|
||||
'partner_id': partner_id,
|
||||
'exclude_from_invoice_tab': True,
|
||||
|
||||
}
|
||||
move_line_values.append(move_line_dst)
|
||||
|
||||
move_line_values_by_expense[expense.id] = move_line_values
|
||||
return move_line_values_by_expense
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -18,23 +18,23 @@ class HrExpenseSheetPledge(models.Model):
|
|||
|
||||
custody_bank_journal_id = fields.Many2one(
|
||||
'account.journal',
|
||||
string='Custody Journal',
|
||||
domain=[('custody_journal', '=', True)],
|
||||
)
|
||||
custody_partner_id = fields.Many2one('res.partner', string='Custody Partner')
|
||||
string='Journal',
|
||||
domain="[('custody_journal', '=', True), ('type', 'in', ['purchase'])]",
|
||||
|
||||
@api.depends('custody_bank_journal_id', 'bank_journal_id')
|
||||
def _compute_available_account_payment_method_ids(self):
|
||||
AccountPaymentMethodLine = self.env['account.payment.method.line'].sudo()
|
||||
for rec in self:
|
||||
if rec.payment_mode == 'custody' and rec.custody_bank_journal_id:
|
||||
rec.available_account_payment_method_ids = AccountPaymentMethodLine.search(
|
||||
[('id', 'in', rec.custody_bank_journal_id.outbound_payment_method_line_ids.ids)])
|
||||
elif rec.bank_journal_id:
|
||||
rec.available_account_payment_method_ids = AccountPaymentMethodLine.search(
|
||||
[('id', 'in', rec.bank_journal_id.outbound_payment_method_line_ids.ids)])
|
||||
else:
|
||||
rec.available_account_payment_method_ids = False
|
||||
)
|
||||
custody_partner_id = fields.Many2one('res.partner', string='Partner')
|
||||
@api.onchange('employee_id')
|
||||
def _onchange_employee_id_set_custody_partner(self):
|
||||
if self.employee_id and self.employee_id.address_home_id:
|
||||
self.custody_partner_id = self.employee_id.address_home_id.id
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if vals.get('employee_id') and not vals.get('custody_partner_id'):
|
||||
employee = self.env['hr.employee'].browse(vals['employee_id'])
|
||||
if employee.address_home_id:
|
||||
vals['custody_partner_id'] = employee.address_home_id.id
|
||||
return super().create(vals)
|
||||
|
||||
def action_submit_sheet(self):
|
||||
for rec in self:
|
||||
|
|
@ -43,33 +43,22 @@ class HrExpenseSheetPledge(models.Model):
|
|||
_("When the payment type is custody, you must set the Custody Partner before submitting."))
|
||||
return super(HrExpenseSheetPledge, self).action_submit_sheet()
|
||||
|
||||
def _get_custody_partner_domain(self):
|
||||
if not self.custody_bank_journal_id:
|
||||
return [('id', '=', False)]
|
||||
|
||||
pledge_requests = self.env['hr.request.pledge'].search([
|
||||
('journal_id', '=', self.custody_bank_journal_id.id),
|
||||
('remaining_amount', '>', 0),
|
||||
])
|
||||
employee_ids = pledge_requests.mapped('employee_id')
|
||||
partner_ids = []
|
||||
for employee in employee_ids:
|
||||
if employee.user_id and employee.user_id.partner_id:
|
||||
partner_ids.append(employee.user_id.partner_id.id)
|
||||
if not partner_ids:
|
||||
return [('id', '=', False)]
|
||||
return [('id', 'in', partner_ids)]
|
||||
|
||||
@api.onchange('payment_mode')
|
||||
def _onchange_payment_mode(self):
|
||||
"""Reset fields when payment mode changes"""
|
||||
if self.payment_mode == 'custody':
|
||||
self.bank_journal_id = False
|
||||
self.account_payment_method_id = False
|
||||
self.custody_partner_id = False
|
||||
else:
|
||||
self.custody_bank_journal_id = False
|
||||
self.custody_partner_id = False
|
||||
self.custody_bank_journal_id = False
|
||||
self.bank_journal_id = False
|
||||
self.account_payment_method_id = False
|
||||
|
||||
# if self.payment_mode == 'custody':
|
||||
# self.bank_journal_id = False
|
||||
# self.account_payment_method_id = False
|
||||
# # self.custody_partner_id = False
|
||||
# else:
|
||||
# self.custody_bank_journal_id = False
|
||||
# self.custody_partner_id = False
|
||||
|
||||
@api.onchange('custody_bank_journal_id')
|
||||
def _onchange_custody_bank_journal_id(self):
|
||||
|
|
@ -78,22 +67,36 @@ class HrExpenseSheetPledge(models.Model):
|
|||
self.bank_journal_id = self.custody_bank_journal_id
|
||||
|
||||
self.account_payment_method_id = False
|
||||
self.custody_partner_id = False
|
||||
return {'domain': {'custody_partner_id': self._get_custody_partner_domain()}}
|
||||
|
||||
@api.onchange('bank_journal_id')
|
||||
def _onchange_bank_journal_id(self):
|
||||
self.account_payment_method_id = False
|
||||
if self.payment_mode == 'custody':
|
||||
self.custody_partner_id = False
|
||||
return {'domain': {'custody_partner_id': self._get_custody_partner_domain()}}
|
||||
# self.custody_partner_id = False
|
||||
# return {'domain': {'custody_partner_id': self._get_custody_partner_domain()}}
|
||||
|
||||
def action_sheet_move_create(self):
|
||||
"""Override to handle custody like company_account"""
|
||||
res = super().action_sheet_move_create()
|
||||
|
||||
custody_sheets = self.filtered(lambda sheet: sheet.payment_mode == 'custody' and sheet.expense_line_ids)
|
||||
custody_sheets = self.filtered(lambda sheet: sheet.expense_line_ids)
|
||||
if custody_sheets:
|
||||
for sheet in custody_sheets:
|
||||
print("🧾 Sheet ID %s current state: %s", sheet.id, sheet.state)
|
||||
if custody_sheets.account_move_id:
|
||||
custody_sheets.account_move_id.write({'move_type': 'in_receipt'})
|
||||
custody_sheets.paid_expense_sheets()
|
||||
|
||||
return res
|
||||
|
||||
def approve_expense_sheets(self):
|
||||
for sheet in self:
|
||||
if sheet.payment_mode == 'custody':
|
||||
employee = sheet.employee_id
|
||||
available_pledges = self.env['hr.request.pledge'].sudo().search([
|
||||
('employee_id', '=', employee.id),
|
||||
('custody_status', 'in', ['partial', 'new']),
|
||||
])
|
||||
available_pledges = available_pledges.filtered(
|
||||
lambda p: p.custody_status in ['partial', 'new'] and p.state == 'pay'
|
||||
)
|
||||
if not available_pledges:
|
||||
raise UserError(
|
||||
_("The employee %s has no available custody balance to cover this expense sheet.") % employee.name
|
||||
)
|
||||
return super().approve_expense_sheets()
|
||||
|
|
@ -5,6 +5,10 @@ from odoo import api, fields, models, tools, _
|
|||
import ast
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.tools import float_compare, float_is_zero
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# class HrEmployee(models.Model):
|
||||
|
|
@ -20,15 +24,7 @@ from odoo.tools import float_compare, float_is_zero
|
|||
# return action
|
||||
|
||||
|
||||
class BaseDashboardExtended(models.Model):
|
||||
_inherit = 'base.dashbord' # Inherit existing dashboard
|
||||
|
||||
# One2many reverse of the Many2one in pledges
|
||||
pledge_ids = fields.One2many(
|
||||
'hr.request.pledge',
|
||||
'dashboard_id',
|
||||
|
||||
)
|
||||
|
||||
class HrRequestPledge(models.Model):
|
||||
_name = 'hr.request.pledge'
|
||||
|
|
@ -42,10 +38,10 @@ class HrRequestPledge(models.Model):
|
|||
('submit', _('Waiting Payroll Officer')),
|
||||
('direct_manager', _('Wait HR Department')),
|
||||
('hr_manager', _('Wait GM Approval')),
|
||||
|
||||
('executive_manager', _('Wait Transfer')),
|
||||
('financial_approve', _('Wait Financial Approval')),
|
||||
('pay', _('Transferred')), ('refused', _('Refused')),
|
||||
('locked', _('Locked')),
|
||||
('closed', _('Loan Suspended'))],
|
||||
default="draft", tracking=True)
|
||||
date = fields.Date(required=True)
|
||||
|
|
@ -57,10 +53,10 @@ class HrRequestPledge(models.Model):
|
|||
|
||||
index=True
|
||||
)
|
||||
is_financial_impact = fields.Boolean(
|
||||
compute='_compute_is_financial_impact',
|
||||
store=True
|
||||
)
|
||||
# is_financial_impact = fields.Boolean(
|
||||
# compute='_compute_is_financial_impact',
|
||||
# store=True
|
||||
# )
|
||||
custody_type_id = fields.Many2one(
|
||||
'custody.types',
|
||||
string='Custody Types',
|
||||
|
|
@ -82,7 +78,13 @@ class HrRequestPledge(models.Model):
|
|||
string='Currency',
|
||||
default=lambda self: self.env.company.currency_id
|
||||
)
|
||||
|
||||
company_id = fields.Many2one(
|
||||
"res.company",
|
||||
string="Company",
|
||||
default=lambda self: self.env.company,
|
||||
required=True,
|
||||
readonly=True
|
||||
)
|
||||
spent_amount = fields.Float(string="Amount Spent", default=0.0)
|
||||
remaining_amount = fields.Float(string="Amount Remaining", compute="_compute_remaining_amount", store=True)
|
||||
custody_status = fields.Selection([
|
||||
|
|
@ -90,32 +92,169 @@ class HrRequestPledge(models.Model):
|
|||
('partial', 'Partial'),
|
||||
('paid', 'Paid'),
|
||||
('exceeded', 'Exceeded')
|
||||
], string='Custody Status', default='new', tracking=True)
|
||||
],compute='_compute_custody_status', string='Custody Status', default='new', tracking=True)
|
||||
|
||||
@api.depends('spent_amount', 'emp_expect_amount')
|
||||
|
||||
payment_ids = fields.One2many(
|
||||
'account.payment', 'hr_request_pledge_id',
|
||||
string="Payments"
|
||||
)
|
||||
total_paid_amount = fields.Float(
|
||||
string="Total Paid Amount",
|
||||
compute='_compute_total_paid_amount',
|
||||
store=True
|
||||
)
|
||||
permanent_pledge = fields.Boolean(
|
||||
string="Permanent Pledge",
|
||||
default=False,
|
||||
)
|
||||
spent_amount_computed = fields.Float(
|
||||
string="Computed Spent Amount",
|
||||
compute="_compute_spent_amount_from_moves",
|
||||
store=True,
|
||||
help="Automatically distributed from related expense journal entries by employee."
|
||||
)
|
||||
total_refunded_amount = fields.Float(
|
||||
string="Total Refunded Amount",
|
||||
compute='_compute_total_refunded_amount',
|
||||
store=True
|
||||
)
|
||||
|
||||
@api.depends('payment_ids.amount', 'payment_ids.state', 'payment_ids.payment_type')
|
||||
def _compute_total_refunded_amount(self):
|
||||
for rec in self:
|
||||
# Filter posted inbound payments
|
||||
posted_payments = rec.payment_ids.filtered(lambda p: p.state == 'posted')
|
||||
inbound_total = sum(posted_payments.filtered(lambda p: p.payment_type == 'inbound').mapped('amount'))
|
||||
rec.total_refunded_amount = inbound_total
|
||||
def action_lock_pledge(self):
|
||||
for record in self:
|
||||
if record.remaining_amount > 0:
|
||||
raise UserError(_("You cannot close this pledge because there is a remaining amount of %.2f.") % record.remaining_amount)
|
||||
record.state = 'locked'
|
||||
|
||||
@api.depends('employee_id', 'total_paid_amount')
|
||||
def _compute_spent_amount_from_moves(self):
|
||||
Move = self.env['account.move']
|
||||
all_employees = self.mapped('employee_id')
|
||||
|
||||
for emp in all_employees:
|
||||
moves = Move.search([
|
||||
('move_type', 'in', ['in_receipt', 'in_invoice']),
|
||||
('is_petty_paid', '=', True),
|
||||
('state', '=', 'posted'),
|
||||
('petty_employee_id', '=', emp.id),
|
||||
])
|
||||
total_spent = 0.0
|
||||
for move in moves:
|
||||
total_spent += sum(move.line_ids.filtered(lambda l: l.debit > 0).mapped('debit'))
|
||||
pledges = self.search([('employee_id', '=', emp.id), ('state', 'in', ['pay', 'locked'])], order='id asc')
|
||||
|
||||
remaining = total_spent
|
||||
|
||||
for pledge in pledges:
|
||||
if remaining <= 0:
|
||||
pledge.spent_amount_computed = 0.0
|
||||
pledge.spent_amount = 0.0
|
||||
continue
|
||||
|
||||
limit = pledge.total_paid_amount or 0.0
|
||||
|
||||
if remaining >= limit and limit > 0:
|
||||
pledge.spent_amount_computed = limit
|
||||
pledge.spent_amount = limit
|
||||
remaining -= limit
|
||||
else:
|
||||
pledge.spent_amount_computed = remaining
|
||||
pledge.spent_amount = remaining
|
||||
remaining = 0
|
||||
|
||||
if remaining > 0 and pledges:
|
||||
pledges[-1].spent_amount_computed += remaining
|
||||
pledges[-1].spent_amount += remaining
|
||||
|
||||
@api.depends('spent_amount', 'total_paid_amount')
|
||||
def _compute_custody_status(self):
|
||||
for pledge in self:
|
||||
remaining = (pledge.total_paid_amount or 0.0) - (pledge.spent_amount or 0.0)
|
||||
if remaining > 0:
|
||||
pledge.custody_status = 'partial'
|
||||
elif remaining == 0:
|
||||
pledge.custody_status = 'paid'
|
||||
else:
|
||||
pledge.custody_status = 'exceeded'
|
||||
|
||||
# @api.depends('payment_ids.amount', 'payment_ids.state', 'payment_ids.payment_type')
|
||||
# def _compute_total_paid_amount(self):
|
||||
# for rec in self:
|
||||
# posted_outbound_payments = rec.payment_ids.filtered(
|
||||
# lambda p: p.state == 'posted' and p.payment_type == 'outbound')
|
||||
# rec.total_paid_amount = sum(posted_outbound_payments.mapped('amount'))
|
||||
|
||||
@api.depends('payment_ids.amount', 'payment_ids.state', 'payment_ids.payment_type')
|
||||
def _compute_total_paid_amount(self):
|
||||
for rec in self:
|
||||
posted_payments = rec.payment_ids.filtered(lambda p: p.state == 'posted')
|
||||
|
||||
outbound_total = sum(posted_payments.filtered(lambda p: p.payment_type == 'outbound').mapped('amount'))
|
||||
|
||||
|
||||
rec.total_paid_amount = outbound_total
|
||||
|
||||
@api.depends('spent_amount', 'total_paid_amount')
|
||||
def _compute_remaining_amount(self):
|
||||
for rec in self:
|
||||
rec.remaining_amount = (rec.emp_expect_amount or 0.0) - (rec.spent_amount or 0.0)
|
||||
rec.remaining_amount = (rec.total_paid_amount or 0.0) - (rec.spent_amount or 0.0) - (rec.total_refunded_amount or 0.0)
|
||||
|
||||
@api.model
|
||||
def search(self, args, offset=0, limit=None, order=None, count=False):
|
||||
if not self.env.su:
|
||||
user_company_ids = self.env.user.company_ids.ids
|
||||
company_domain = [('company_id', 'in', user_company_ids)]
|
||||
args = args + company_domain
|
||||
return super(HrRequestPledge, self).search(args, offset=offset, limit=limit, order=order, count=count)
|
||||
|
||||
@api.model
|
||||
def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None):
|
||||
|
||||
if not self.env.context.get('skip_company_check'):
|
||||
company_domain = [('company_id', 'in', self.env.user.company_ids.ids)]
|
||||
domain = (domain or []) + company_domain
|
||||
|
||||
return super(HrRequestPledge, self).search_read(
|
||||
domain, fields, offset, limit, order
|
||||
)
|
||||
|
||||
@api.model
|
||||
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
|
||||
if not self.env.su:
|
||||
user_company_ids = self.env.user.company_ids.ids
|
||||
company_domain = [('company_id', 'in', user_company_ids)]
|
||||
domain = domain + company_domain
|
||||
return super(HrRequestPledge, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
|
||||
|
||||
# def unlink(self):
|
||||
# for i in self:
|
||||
# if i.state != 'draft':
|
||||
# raise UserError(_('You can not delete record in state not in draft'))
|
||||
# return super(HrRequestPledge, self).unlink()
|
||||
|
||||
|
||||
@api.model
|
||||
def allocate_payment_to_pledges(self, employee_id, journal_id, amount):
|
||||
def allocate_payment_to_pledges(self, employee_id, amount):
|
||||
"""
|
||||
Allocate a payment amount to employee's custody requests ordered by oldest.
|
||||
Handles partial, full, and exceeded states.
|
||||
"""
|
||||
print(f"🚀 allocate_payment_to_pledges called | employee_id={employee_id} | amount={amount}")
|
||||
|
||||
remaining_amount = amount
|
||||
|
||||
pledges = self.search([
|
||||
('employee_id', '=', employee_id),
|
||||
('journal_id', '=', journal_id),
|
||||
('custody_status', 'in', ['partial','new' ]),
|
||||
], order="id asc")
|
||||
print(f"🔍 pledges found: {pledges}")
|
||||
|
||||
for pledge in pledges:
|
||||
if remaining_amount <= 0:
|
||||
|
|
@ -160,14 +299,17 @@ class HrRequestPledge(models.Model):
|
|||
"The requested amount (%s) exceeds the maximum allowed for the selected custody type (%s)."
|
||||
) % (record.emp_expect_amount, record.custody_type_id.max_custody_amount))
|
||||
|
||||
@api.depends('dashboard_id.is_financial_impact')
|
||||
def _compute_is_financial_impact(self):
|
||||
for record in self:
|
||||
|
||||
record.is_financial_impact = record.dashboard_id.is_financial_impact
|
||||
|
||||
|
||||
# @api.depends('dashboard_id.pledge_ids.is_financial_impact')
|
||||
# def _compute_is_financial_impact(self):
|
||||
# for record in self:
|
||||
# if record.dashboard_id:
|
||||
# record.is_financial_impact = any(
|
||||
# pledge.is_financial_impact for pledge in record.dashboard_id.pledge_ids
|
||||
# )
|
||||
# else:
|
||||
# record.is_financial_impact = False
|
||||
|
||||
# record.is_financial_impact = record.dashboard_id.pledge_ids.is_financial_impact
|
||||
|
||||
def get_user_id(self):
|
||||
employee_id = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
|
||||
|
|
@ -229,77 +371,213 @@ class HrRequestPledge(models.Model):
|
|||
def cancel(self):
|
||||
self.state = "cancel"
|
||||
|
||||
def action_open_confirm_wizard(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'name': _('Confirmation Wizard for Pledge Payment'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'hr.request.pledge.confirm.wizard',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_pledge_id': self.id,
|
||||
'default_action_type': self._context.get('action_type'),
|
||||
},
|
||||
}
|
||||
|
||||
def pay(self):
|
||||
|
||||
if not self.journal_id:
|
||||
raise ValidationError(_('Please set the journal for this employee.'))
|
||||
|
||||
employee_partner = self.employee_id.user_id.partner_id
|
||||
if not employee_partner:
|
||||
raise ValidationError(_('Employee must have a related partner.'))
|
||||
action_type = self.env.context.get('action_type', 'create')
|
||||
if action_type == 'feed':
|
||||
amount = self.spent_amount or 0.0
|
||||
if amount <= 0:
|
||||
raise ValidationError(_('Spent amount must be greater than zero for feeding the pledge.'))
|
||||
else:
|
||||
amount = self.emp_expect_amount or 0.0
|
||||
|
||||
payment_vals = {
|
||||
'payment_type': 'inbound',
|
||||
'payment_type': 'outbound',
|
||||
'partner_type': 'supplier',
|
||||
'is_internal_transfer': True,
|
||||
'amount': self.emp_expect_amount,
|
||||
'skip_paired_payment': True,
|
||||
'amount': amount,
|
||||
'journal_id': self.journal_id.id,
|
||||
'date': fields.datetime.today(),
|
||||
'ref': self.description,
|
||||
'hr_request_pledge': self.id,
|
||||
'hr_request_pledge_id': self.id,
|
||||
'partner_id': employee_partner.id,
|
||||
'petty_cash_pledge':True
|
||||
}
|
||||
|
||||
payment = self.env['account.payment'].create(payment_vals)
|
||||
payment.flush()
|
||||
payment.refresh()
|
||||
|
||||
employee_partner = self.employee_id.user_id.partner_id
|
||||
if employee_partner:
|
||||
for line in payment.move_id.line_ids:
|
||||
if line.debit > 0:
|
||||
line.partner_id = employee_partner.id
|
||||
break
|
||||
# employee_partner = self.employee_id.user_id.partner_id
|
||||
# if employee_partner and payment.move_id:
|
||||
# debit_lines = payment.move_id.line_ids.filtered(lambda l: l.debit > 0)
|
||||
# if debit_lines:
|
||||
# debit_lines.write({'partner_id': employee_partner.id})
|
||||
|
||||
self.state = "pay"
|
||||
return payment
|
||||
if action_type == 'create':
|
||||
self.state = "pay"
|
||||
|
||||
if action_type == 'feed':
|
||||
message = _("✅ The pledge has been successfully funded with an amount of %.2f.") % amount
|
||||
else:
|
||||
message = _("✅ A new pledge has been successfully created with an amount of %.2f.") % amount
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'title': _('Operation Successful'),
|
||||
'message': message,
|
||||
'type': 'success',
|
||||
'sticky': False,
|
||||
'next': {'type': 'ir.actions.act_window_close'},
|
||||
}
|
||||
}
|
||||
|
||||
def refund_remaining_amount(self):
|
||||
for rec in self:
|
||||
if rec.remaining_amount <= 0:
|
||||
raise ValidationError(_('There is no remaining amount to refund.'))
|
||||
if not rec.journal_id:
|
||||
raise ValidationError(_('Please set the journal for this employee.'))
|
||||
employee_partner = rec.employee_id.user_id.partner_id
|
||||
if not employee_partner:
|
||||
raise ValidationError(_('Employee must have a related partner.'))
|
||||
amount = rec.remaining_amount
|
||||
payment_vals = {
|
||||
'payment_type': 'inbound',
|
||||
'partner_type': 'customer',
|
||||
'is_internal_transfer': True,
|
||||
'skip_paired_payment': True,
|
||||
'amount': amount,
|
||||
'journal_id': rec.journal_id.id,
|
||||
'date': fields.datetime.today(),
|
||||
'ref': _('Refund of pledge: %s') % rec.code,
|
||||
'hr_request_pledge_id': rec.id,
|
||||
'partner_id': employee_partner.id,
|
||||
'petty_cash_pledge': True,
|
||||
}
|
||||
payment = self.env['account.payment'].create(payment_vals)
|
||||
payment.flush()
|
||||
payment.refresh()
|
||||
message = _("تم إرجاع المبلغ")
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'title': _('Operation Successful'),
|
||||
'message': message,
|
||||
'type': 'success',
|
||||
'sticky': False,
|
||||
'next': {'type': 'ir.actions.act_window_close'},
|
||||
}
|
||||
}
|
||||
|
||||
def action_open_refund_payments(self):
|
||||
refund_payments = self.env['account.payment'].search([
|
||||
'|',
|
||||
('hr_request_pledge_id', '=', self.id),
|
||||
('hr_request_pledge', '=', self.id),
|
||||
('payment_type', '=', 'inbound'),
|
||||
])
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': 'Refund Payments',
|
||||
'res_model': 'account.payment',
|
||||
'domain': [('id', 'in', refund_payments.ids)] if refund_payments else [('id', '=', False)],
|
||||
'view_mode': 'tree,form',
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
def financialApproval(self):
|
||||
self.state="financial_approve"
|
||||
self.state = "financial_approve"
|
||||
|
||||
|
||||
def action_open_payment_confirmation(self):
|
||||
"""
|
||||
"""
|
||||
return {
|
||||
'name': _('Confirm Payment'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'hr.request.pledge.pay.wizard',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': {'default_pledge_id': self.id, 'action_type': self.env.context.get('action_type')}
|
||||
}
|
||||
|
||||
def action_account_payment_budget_pledge(self):
|
||||
budget_account_payment = self.env['account.payment'].search(
|
||||
[('hr_request_pledge', '=', self.id)],
|
||||
limit=1
|
||||
)
|
||||
treeview_ref = self.env.ref('account.view_account_payment_tree', False) # tree view
|
||||
formview_ref = self.env.ref('odex25_account_saip.view_account_payment_new_approve_form', False)
|
||||
budget_account_payment = self.env['account.payment'].search([
|
||||
'|',
|
||||
('hr_request_pledge_id', '=', self.id),
|
||||
('hr_request_pledge', '=', self.id),
|
||||
('payment_type', '=', 'outbound'),
|
||||
])
|
||||
|
||||
if budget_account_payment:
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': 'Achieving Budget',
|
||||
'res_model': 'account.payment',
|
||||
'res_id': budget_account_payment.id,
|
||||
'view_mode': 'form',
|
||||
'domain': [('id', 'in', budget_account_payment.ids)] if budget_account_payment else [],
|
||||
'view_mode': 'tree,form',
|
||||
'views': [
|
||||
(treeview_ref.id, 'tree') if treeview_ref else (False, 'tree'),
|
||||
(formview_ref.id, 'form') if formview_ref else (False, 'form'),
|
||||
],
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
|
||||
class SmartButtonReturnRequestPledge(models.Model):
|
||||
_inherit = "account.payment"
|
||||
hr_request_pledge = fields.Many2one('hr.request.pledge')
|
||||
|
||||
def action_go_to_hr_request_pledge(self):
|
||||
pledge_record = self.env['hr.request.pledge'].search(
|
||||
[('id', '=', self.hr_request_pledge.id)],
|
||||
limit=1
|
||||
|
||||
class AccountMove(models.Model):
|
||||
_inherit = 'account.move'
|
||||
|
||||
def action_post(self):
|
||||
res = super(AccountMove, self).action_post()
|
||||
|
||||
petty_moves = self.filtered(lambda m:
|
||||
m.move_type in ['in_receipt', 'in_invoice'] and
|
||||
m.is_petty_paid and
|
||||
m.state == 'posted'
|
||||
)
|
||||
if pledge_record:
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': 'HR Request Pledge',
|
||||
'res_model': 'hr.request.pledge',
|
||||
'res_id': pledge_record.id,
|
||||
'view_mode': 'form',
|
||||
'view_type': 'form',
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
if petty_moves:
|
||||
employees = petty_moves.mapped('petty_employee_id')
|
||||
if employees:
|
||||
pledges = self.env['hr.request.pledge'].search([
|
||||
('employee_id', 'in', employees.ids),
|
||||
('state', 'in', ['pay', 'locked'])
|
||||
])
|
||||
if pledges:
|
||||
pledges._compute_spent_amount_from_moves()
|
||||
|
||||
return res
|
||||
|
||||
|
||||
|
||||
class BaseDashboardExtended(models.Model):
|
||||
_inherit = 'base.dashbord' # Inherit existing dashboard
|
||||
|
||||
pledge_ids = fields.One2many(
|
||||
'hr.request.pledge',
|
||||
'dashboard_id',
|
||||
|
||||
)
|
||||
|
||||
|
||||
class EmployeeJournal(models.Model):
|
||||
|
|
@ -318,59 +596,6 @@ class EmployeeJournal(models.Model):
|
|||
|
||||
|
||||
|
||||
# def action_sheet_move_create(self):
|
||||
# for sheet in self:
|
||||
# if sheet.payment_mode == 'company_account' and not (sheet.bank_journal_id and sheet.account_payment_method_id):
|
||||
# raise UserError(
|
||||
# _("Please enter Bank Journal and Payment Method!")
|
||||
# )
|
||||
#
|
||||
# return super(HrExpenseSheetPledge, self).action_sheet_move_create()
|
||||
|
||||
|
||||
# class AchievingBudgetAchievingBudget(models.Model):
|
||||
# _inherit = "hr.expense"
|
||||
|
||||
# action_budget_id = fields.Many2one('account.tax', 'analytic')
|
||||
|
||||
# def _create_sheet_from_expenses(self):
|
||||
# if any(expense.state != 'draft' or expense.sheet_id for expense in self):
|
||||
# raise UserError(_("You cannot report twice the same line!"))
|
||||
# if len(self.mapped('employee_id')) != 1:
|
||||
# raise UserError(_("You cannot report expenses for different employees in the same report."))
|
||||
# if any(not expense.product_id for expense in self):
|
||||
# raise UserError(_("You can not create report without product."))
|
||||
# if len(self.company_id) != 1:
|
||||
# raise UserError(_("You cannot report expenses for different companies in the same report."))
|
||||
|
||||
# todo = self.filtered(lambda x: x.payment_mode=='own_account') or self.filtered(lambda x: x.payment_mode=='company_account')
|
||||
# sheet = self.env['hr.expense.sheet'].create({
|
||||
# 'company_id': self.company_id.id,
|
||||
# 'employee_id': self[0].employee_id.id,
|
||||
# 'name': todo[0].name if len(todo) == 1 else '',
|
||||
# 'expense_line_ids': [(6, 0, todo.ids)],
|
||||
# })
|
||||
# # sheet.write({
|
||||
# # 'account_payment_method_id': sheet.bank_journal_id.outbound_payment_method_line_ids[:1]
|
||||
# # })
|
||||
# return sheet
|
||||
|
||||
# def action_achieving_budget_pledge(self):
|
||||
# achieving_budget_record = self.env['budget.confirmation'].search(
|
||||
# [('expense_id', '=', self.id)],
|
||||
# limit=1
|
||||
# )
|
||||
# if achieving_budget_record:
|
||||
# return {
|
||||
# 'type': 'ir.actions.act_window',
|
||||
# 'name': 'Achieving Budget',
|
||||
# 'res_model': 'budget.confirmation',
|
||||
# 'res_id': achieving_budget_record.id,
|
||||
# 'view_mode': 'form',
|
||||
# 'target': 'current',
|
||||
# }
|
||||
|
||||
|
||||
class MoveLine(models.Model):
|
||||
_inherit = 'account.move.line'
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class CustodyTypes(models.Model):
|
|||
'account.journal',
|
||||
string='Journal',
|
||||
required=True,
|
||||
domain="[('custody_journal', '=', True)]",
|
||||
domain="[('custody_journal', '=', True), ('type', 'in', ['bank','cash'])]",
|
||||
help='Select the journal associated with this type of custody'
|
||||
)
|
||||
|
||||
|
|
@ -27,6 +27,48 @@ class CustodyTypes(models.Model):
|
|||
help='The maximum amount allowed for this type of custody'
|
||||
)
|
||||
|
||||
company_id = fields.Many2one(
|
||||
"res.company",
|
||||
string="Company",
|
||||
default=lambda self: self.env.company,
|
||||
required=True,
|
||||
readonly=True
|
||||
|
||||
)
|
||||
@api.model
|
||||
def search(self, args, offset=0, limit=None, order=None, count=False):
|
||||
if not self.env.su:
|
||||
user_company_ids = self.env.user.company_ids.ids
|
||||
company_domain = [('company_id', 'in', user_company_ids)]
|
||||
args = args + company_domain
|
||||
return super(CustodyTypes, self).search(args, offset=offset, limit=limit, order=order, count=count)
|
||||
|
||||
|
||||
@api.model
|
||||
def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None):
|
||||
|
||||
if not self.env.context.get('skip_company_check'):
|
||||
company_domain = [('company_id', 'in', self.env.user.company_ids.ids)]
|
||||
domain = (domain or []) + company_domain
|
||||
|
||||
return super(CustodyTypes, self).search_read(
|
||||
domain, fields, offset, limit, order
|
||||
)
|
||||
@api.model
|
||||
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
|
||||
if not self.env.su:
|
||||
user_company_ids = self.env.user.company_ids.ids
|
||||
company_domain = [('company_id', 'in', user_company_ids)]
|
||||
domain = domain + company_domain
|
||||
return super(CustodyTypes, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
|
||||
@api.model
|
||||
def name_search(self, name='', args=None, operator='ilike', limit=100):
|
||||
args = args or []
|
||||
if not self.env.su:
|
||||
user_company_ids = self.env.user.company_ids.ids
|
||||
args = args + [('company_id', 'in', user_company_ids)]
|
||||
return super(CustodyTypes, self).name_search(name=name, args=args, operator=operator, limit=limit)
|
||||
|
||||
@api.constrains('max_custody_amount')
|
||||
def _check_max_custody_amount(self):
|
||||
for record in self:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_hr_request_pledge_user,access_hr_request_pledge_user,model_hr_request_pledge,,1,1,1,1
|
||||
|
||||
access_hr_request_pledge_confirm_wizard,access_hr_request_pledge_confirm_wizard,model_hr_request_pledge_confirm_wizard,,1,1,1,1
|
||||
access_custody_types_manager,custody.types.manager,model_custody_types,,1,1,1,1
|
||||
|
|
|
@ -31,23 +31,44 @@
|
|||
<field name="name">Officer</field>
|
||||
<field name="category_id" ref="employee_custody_request.module_category_general_ledger_custom"/>
|
||||
</record>
|
||||
<record id="hr_request_pledge_rule_hr_user" model="ir.rule">
|
||||
<field name="name">HR User: Own Pledges</field>
|
||||
<field name="model_id" ref="employee_custody_request.model_hr_request_pledge"/>
|
||||
<field name="groups" eval="[(4, ref('employee_custody_request.group_hr_user'))]"/>
|
||||
<field name="domain_force">[('employee_id.user_id', '=', user.id)]</field>
|
||||
</record>
|
||||
|
||||
<record id="group_loan_manager" model="res.groups">
|
||||
<field name="name">Loan Manager</field>
|
||||
<field name="category_id" ref="employee_custody_request.module_category_general_ledger_custom"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="group_hr_manager" model="res.groups">
|
||||
<field name="name">Administrator</field>
|
||||
<field name="category_id" ref="employee_custody_request.module_category_general_ledger_custom"/>
|
||||
</record>
|
||||
|
||||
<record id="group_general_manager" model="res.groups">
|
||||
<field name="name">General Manager</field>
|
||||
<field name="category_id" ref="employee_custody_request.module_category_general_ledger_custom"/>
|
||||
</record>
|
||||
|
||||
<record id="group_account_manager" model="res.groups">
|
||||
<field name="name">Accounting Manager</field>
|
||||
<field name="category_id" ref="employee_custody_request.module_category_general_ledger_custom"/>
|
||||
</record>
|
||||
<record id="hr_request_pledge_rule_loan_manager" model="ir.rule">
|
||||
<field name="name"> All Pledges</field>
|
||||
<field name="model_id" ref="employee_custody_request.model_hr_request_pledge"/>
|
||||
<field name="groups" eval="[(4, ref('employee_custody_request.group_loan_manager')),
|
||||
(4, ref('employee_custody_request.group_general_manager')),
|
||||
(4, ref('employee_custody_request.group_hr_manager')),
|
||||
(4, ref('employee_custody_request.group_account_manager')),
|
||||
]"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
</record>
|
||||
|
||||
<record id="group_employee_custody_report" model="res.groups">
|
||||
<field name="name">Employee Custody Report</field>
|
||||
<field name="category_id" ref="employee_custody_request.module_category_general_ledger_custom"/>
|
||||
|
|
|
|||
|
|
@ -4,11 +4,18 @@
|
|||
<field name="model">hr.expense.sheet</field>
|
||||
<field name="inherit_id" ref="hr_expense.view_hr_expense_sheet_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='bank_journal_id']" position="after">
|
||||
<field name="custody_bank_journal_id" attrs="{'invisible': [('payment_mode', '!=', 'custody')]}"/>
|
||||
<xpath expr="//field[@name='bank_journal_id']" position="replace">
|
||||
<field name="custody_bank_journal_id" required="1" />
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='custody_bank_journal_id']" position="after">
|
||||
<field name="custody_partner_id" attrs="{'invisible': [('payment_mode', '!=', 'custody')]}"/>
|
||||
<field name="custody_partner_id" readonly="True"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='journal_id']" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//button[@name='action_register_payment']" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
|
||||
</xpath>
|
||||
|
||||
</field>
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@
|
|||
<field name="journal_id"/>
|
||||
<field name="max_custody_amount"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="company_id"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
</sheet>
|
||||
|
|
|
|||
|
|
@ -50,8 +50,17 @@
|
|||
class="oe_stat_button" icon="fa-bars"
|
||||
attrs="{'invisible': [('hr_request_pledge', '=', False)]}"/>
|
||||
</xpath> -->
|
||||
|
||||
<xpath expr="//field[@name='is_internal_transfer']" position="attributes">
|
||||
<attribute name="attrs">{'readonly': [('petty_cash_pledge', '=', True)]}</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='payment_type']" position="after">
|
||||
<field name="hr_request_pledge" invisible="1"/>
|
||||
<field name="hr_request_pledge_id" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='move_id']" position="after">
|
||||
<field name="petty_cash_pledge" readonly="1" attrs="{'invisible': [('petty_cash_pledge','=',False)]}"/>
|
||||
<field name="original_move_id" readonly="1" attrs="{'invisible': [('original_move_id','=',False)]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
|
||||
|
|
@ -62,45 +71,59 @@
|
|||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header>
|
||||
<button name="action_lock_pledge"
|
||||
string="Close Pledge"
|
||||
type="object"
|
||||
class="btn-primary"
|
||||
states="pay"/>
|
||||
<button name="submit" string="Submit" class="oe_highlight" type="object"
|
||||
states="draft" groups="employee_custody_request.group_hr_user"/>
|
||||
<button name="action_open_confirm_wizard" string="Feed Pledge"
|
||||
type="object"
|
||||
class="oe_highlight"
|
||||
context="{'action_type': 'feed'}"
|
||||
groups="employee_custody_request.group_hr_user"
|
||||
attrs="{'invisible': ['|', ('state','!=','pay'), ('permanent_pledge','!=',True)]}"/>
|
||||
<button name="refund_remaining_amount" string="Refund"
|
||||
type="object"
|
||||
class="oe_highlight"
|
||||
groups="employee_custody_request.group_hr_user"
|
||||
attrs="{'invisible': ['|', ('state','!=','pay'), ('permanent_pledge','!=',True)]}"/>
|
||||
|
||||
<button name="direct_manager" string="Payroll Officer Approve" class="oe_highlight"
|
||||
type="object" states="submit" groups="employee_custody_request.group_loan_manager"/>
|
||||
<button name="refused" string="Refuse" states="submit" type="object"
|
||||
class="oe_highlight" groups="employee_custody_request.group_loan_manager"/>
|
||||
|
||||
<button name="hr_manager" string="HR Manager Approve" class="oe_highlight" type="object"
|
||||
states="direct_manager" groups="employee_custody_request.group_hr_manager"/>
|
||||
<button name="refused" string="Refuse" states="direct_manager" type="object"
|
||||
class="oe_highlight" groups="employee_custody_request.group_hr_manager"/>
|
||||
<!-- <button name="hr_manager" string="HR Manager Approve" class="oe_highlight" type="object"-->
|
||||
<!-- states="direct_manager" groups="employee_custody_request.group_hr_manager"/>-->
|
||||
<!-- <button name="refused" string="Refuse" states="direct_manager" type="object"-->
|
||||
<!-- class="oe_highlight" groups="employee_custody_request.group_hr_manager"/>-->
|
||||
|
||||
<button name="executive_manager" string="GM Manager Approve" class="oe_highlight" type="object"
|
||||
states="hr_manager" groups="employee_custody_request.group_general_manager"/>
|
||||
<button name="refused" string="Refuse" states="hr_manager" type="object"
|
||||
states="direct_manager" groups="employee_custody_request.group_general_manager"/>
|
||||
<button name="refused" string="Refuse" states="direct_manager" type="object"
|
||||
class="oe_highlight" groups="employee_custody_request.group_general_manager"/>
|
||||
|
||||
<button name="financialApproval" string="Financial Approval"
|
||||
class="oe_highlight" type="object"
|
||||
|
||||
groups="employee_custody_request.group_account_manager"
|
||||
attrs="{'invisible': ['|',
|
||||
('is_financial_impact', '!=', True),
|
||||
('state', '!=', 'executive_manager')]}"/>
|
||||
<!-- <button name="financialApproval" string="Financial Approval"-->
|
||||
<!-- class="oe_highlight" type="object"-->
|
||||
<!-- -->
|
||||
<!-- groups="employee_custody_request.group_account_manager"-->
|
||||
<!-- attrs="{'invisible': [-->
|
||||
<!-- ('state', '!=', 'executive_manager')]}"/>-->
|
||||
|
||||
|
||||
<button name="pay" string="Transfer"
|
||||
class="oe_highlight" type="object"
|
||||
|
||||
context="{'action_type': 'create'}"
|
||||
groups="employee_custody_request.group_account_manager"
|
||||
attrs="{'invisible': ['|',
|
||||
('is_financial_impact', '!=', False),
|
||||
attrs="{'invisible': [
|
||||
('state', '!=', 'executive_manager')]}"/>
|
||||
|
||||
|
||||
|
||||
<field name="state" widget="statusbar"
|
||||
statusbar_visible="draft,submit,direct_manager,hr_manager,executive_manager,pay,financial_approve,refused"/>
|
||||
statusbar_visible="draft,submit,direct_manager,executive_manager,pay,refused"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
|
|
@ -108,31 +131,46 @@
|
|||
string="Go to account payment"
|
||||
class="oe_stat_button" icon="fa-bars"
|
||||
attrs="{'invisible': [('state', '!=', 'pay')]}"/>
|
||||
<button name="action_open_refund_payments" type="object"
|
||||
string="Show Refunds"
|
||||
class="oe_stat_button" icon="fa-bars"
|
||||
attrs="{'invisible': [('state', '!=', 'pay')]}" />
|
||||
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="is_financial_impact" invisible="1"/>
|
||||
<!-- <field name="is_financial_impact" invisible="1"/>-->
|
||||
|
||||
<field name="code" string="Code" readonly="1"/>
|
||||
<field name="from_hr_depart" string="Another Employee"
|
||||
attrs="{'readonly':[('state','!=','draft')]}"/>
|
||||
<field name="employee_id" string="Employee Name"
|
||||
attrs="{'readonly':['|',('state','!=','draft'),('from_hr_depart','=',False)],'required':True}"/>
|
||||
<field name="date"/>
|
||||
<field name="date" attrs="{'readonly':[('state','!=','draft')]}"/>
|
||||
<field name="company_id"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="emp_expect_amount" attrs="{'readonly':[('state','!=','draft')]}"/>
|
||||
<field name="custody_type_id"/>
|
||||
<field name="custody_type_id" attrs="{'readonly':[('state','!=','draft')]}"/>
|
||||
<field name="journal_id" attrs="{'invisible': [('id', '!=', 0)]}"/>
|
||||
|
||||
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" attrs="{'readonly':[('state','!=','draft')]}"/>
|
||||
<field name="job_id"/>
|
||||
<field name="description"/>
|
||||
<field name="description"
|
||||
attrs="{
|
||||
'required': [('state', '=', 'draft')],
|
||||
'readonly': [('state', '!=', 'draft')]
|
||||
}"/>
|
||||
|
||||
<field name="spent_amount" readonly="1"/>
|
||||
<field name="custody_status" invisible="1"/>
|
||||
|
||||
<field name="remaining_amount"/>
|
||||
<field name="permanent_pledge" attrs="{'readonly':[('state','!=','draft')]}"/>
|
||||
<field name="total_paid_amount"/>
|
||||
<field name="total_refunded_amount"/>
|
||||
<field name="spent_amount_computed" invisible="1"/>
|
||||
|
||||
|
||||
</group>
|
||||
|
|
@ -154,7 +192,9 @@
|
|||
<!-- <field name="from_hr_depart"/>-->
|
||||
<!-- <field name="date"/>-->
|
||||
<field name="employee_id"/>
|
||||
<field name="emp_expect_amount"/>
|
||||
<field name="total_paid_amount"/>
|
||||
<field name="spent_amount" readonly="1"/>
|
||||
<field name="remaining_amount"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
|
@ -171,6 +211,29 @@
|
|||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="view_move_form_visibility_inherit" model="ir.ui.view">
|
||||
<field name="name">account.move.petty.fields.visibility.inherit</field>
|
||||
<field name="model">account.move</field>
|
||||
<field name="inherit_id" ref="petty_invoice.view_move_form"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<xpath expr="//field[@name='is_petty_paid']" position="attributes">
|
||||
<attribute name="attrs">
|
||||
{'invisible': [('move_type', 'not in', ('in_invoice','in_receipt'))]}
|
||||
</attribute>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//field[@name='petty_employee_id']" position="attributes">
|
||||
<attribute name="attrs">
|
||||
{'invisible': [('move_type', 'not in', ('in_invoice','in_receipt'))]}
|
||||
</attribute>
|
||||
</xpath>
|
||||
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_employee_custody_report" model="ir.actions.server">
|
||||
<field name="name">Employee Account</field>
|
||||
<field name="model_id" ref="model_account_move_line"/>
|
||||
|
|
@ -184,11 +247,11 @@
|
|||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
<menuitem id="job_request_pledge" name="Request pledge"
|
||||
action="job_request_action_pledge" parent="hr_expense.menu_hr_expense_my_expenses" sequence="10"
|
||||
action="job_request_action_pledge" parent="account.menu_finance_payables" sequence="4"
|
||||
groups="employee_custody_request.group_general_ledger_manger"/>
|
||||
|
||||
<menuitem id="employee_custody_report_menu" name="Employee Account Report"
|
||||
action="action_employee_custody_report" parent="hr_expense.menu_hr_expense_report" sequence="20"
|
||||
action="action_employee_custody_report" parent="account.menu_finance_payables" sequence="4"
|
||||
groups="employee_custody_request.group_employee_custody_report"/>
|
||||
|
||||
</data>
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
from . import account_payment_register
|
||||
from . import hr_request_pledge_confirm_wizard
|
||||
|
|
|
|||
|
|
@ -150,10 +150,6 @@ class AccountPaymentRegister(models.TransientModel):
|
|||
|
||||
payments = self._create_payments()
|
||||
|
||||
if self._context.get('dont_redirect_to_payments'):
|
||||
return True
|
||||
|
||||
|
||||
# Update `move_id` values to include `takaful_sponsorship_id`
|
||||
# if self.is_refund_sponsorship:
|
||||
# for payment in payments:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
from odoo import models, fields, api, _
|
||||
|
||||
class HrRequestPledgeConfirmWizard(models.TransientModel):
|
||||
_name = 'hr.request.pledge.confirm.wizard'
|
||||
_description = 'Confirmation Wizard for Pledge Payment'
|
||||
|
||||
pledge_id = fields.Many2one('hr.request.pledge', string='Pledge', required=True)
|
||||
action_type = fields.Char(string="Action Type")
|
||||
|
||||
def action_confirm(self):
|
||||
"""Execute the pay() on pledge after confirmation"""
|
||||
self.ensure_one()
|
||||
pledge = self.pledge_id
|
||||
context = dict(self.env.context or {})
|
||||
context['action_type'] = self.action_type
|
||||
result = pledge.with_context(context).pay()
|
||||
return result
|
||||
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<odoo>
|
||||
<record id="view_hr_request_pledge_confirm_wizard_form" model="ir.ui.view">
|
||||
<field name="name">hr.request.pledge.confirm.wizard.form</field>
|
||||
<field name="model">hr.request.pledge.confirm.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Confirm Pledge Action">
|
||||
<group>
|
||||
<div class="o_form_label text-bold">
|
||||
Are you sure you want to feed the pledge?
|
||||
</div>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="action_confirm" string="Confirm" type="object" class="oe_highlight"/>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Loading…
Reference in New Issue