Skip to content

Commit

Permalink
reimbursement portal added
Browse files Browse the repository at this point in the history
  • Loading branch information
RamakrishnaVellala committed Oct 30, 2024
1 parent 73dd294 commit 2210924
Show file tree
Hide file tree
Showing 45 changed files with 3,306 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ addon | version | maintainers | summary
[g2p_program_reimbursement](g2p_program_reimbursement/) | 17.0.0.0.0 | | OpenG2P Programs: Reimbursement
[g2p_programs](g2p_programs/) | 17.0.0.0.0 | | OpenG2P Programs
[g2p_proxy_means_test](g2p_proxy_means_test/) | 17.0.0.0.0 | | G2P: Proxy Means Test
[g2p_reimbursement_portal](g2p_reimbursement_portal/) | 17.0.0.0.0 | | G2P Reimbursement Portal
[g2p_social_registry_importer](g2p_social_registry_importer/) | 17.0.0.0.0 | | Import records from Social Registry
[g2p_theme](g2p_theme/) | 17.0.0.0.0 | | OpenG2P Theme

Expand Down
57 changes: 57 additions & 0 deletions g2p_reimbursement_portal/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
========================
G2P Reimbursement Portal
========================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:4bbe1a58e66a83399a043122ac92dd023b8d6b6737dfb3c48bbd318fa0ccb5a0
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
:target: https://odoo-community.org/page/development-status
:alt: Alpha
.. |badge2| image:: https://img.shields.io/badge/github-OpenG2P%2Fopeng2p--program-lightgray.png?logo=github
:target: https://github.com/OpenG2P/openg2p-program/tree/17.0-develop/g2p_reimbursement_portal
:alt: OpenG2P/openg2p-program

|badge1| |badge2|

OpenG2P Reimbursement Portal

.. IMPORTANT::
This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
`More details on development status <https://odoo-community.org/page/development-status>`_

**Table of contents**

.. contents::
:local:

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OpenG2P/openg2p-program/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OpenG2P/openg2p-program/issues/new?body=module:%20g2p_reimbursement_portal%0Aversion:%2017.0-develop%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
~~~~~~~

* OpenG2P

Maintainers
~~~~~~~~~~~

This module is part of the `OpenG2P/openg2p-program <https://github.com/OpenG2P/openg2p-program/tree/17.0-develop/g2p_reimbursement_portal>`_ project on GitHub.

You are welcome to contribute.
3 changes: 3 additions & 0 deletions g2p_reimbursement_portal/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Part of OpenG2P. See LICENSE file for full copyright and licensing details.
from . import models
from . import controllers
34 changes: 34 additions & 0 deletions g2p_reimbursement_portal/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "G2P Reimbursement Portal",
"category": "G2P",
"version": "17.0.0.0.0",
"sequence": 1,
"author": "OpenG2P",
"website": "https://openg2p.org",
"license": "LGPL-3",
"development_status": "Alpha",
"depends": ["g2p_program_reimbursement", "g2p_agent_portal_base", "g2p_program_cycleless"],
"data": [
"data/g2p_reimbursement_portal_form_data.xml",
"views/g2p_portal_reimbursement.xml",
"views/g2p_portal_form_template.xml",
"views/g2p_portal_form_submitted.xml",
"views/g2p_portal_dashboard.xml",
"views/base.xml",
"views/home.xml",
"views/login.xml",
"views/profile.xml",
"views/website_page.xml",
"views/menu_view.xml",
],
"assets": {
"website.assets_wysiwyg": [
"g2p_reimbursement_portal/static/src/js/reim_form_editor.js",
],
},
"demo": [],
"images": [],
"application": True,
"installable": True,
"auto_install": False,
}
1 change: 1 addition & 0 deletions g2p_reimbursement_portal/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import main
285 changes: 285 additions & 0 deletions g2p_reimbursement_portal/controllers/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
import json
import logging

from werkzeug.datastructures import FileStorage
from werkzeug.exceptions import Forbidden

from odoo import http
from odoo.http import request

from odoo.addons.g2p_agent_portal_base.controllers.main import AgentPortalBase

_logger = logging.getLogger(__name__)


class ReimbursementPortal(AgentPortalBase):
@http.route(["/portal/reimbursement/voucher"], type="http", auth="user", website=True)
def portal_new_entitlements(self, **kwargs):
self.check_roles("Portal")
partner_id = request.env.user.partner_id
entitlements = (
request.env["g2p.entitlement"]
.sudo()
.search(
[
("service_provider_id", "=", partner_id.id),
("state", "=", "approved"),
]
)
)

values = []
for entitlement in entitlements:
# to check no reimbursement claims are already made against this entitlement
is_submitted = len(entitlement.reimbursement_entitlement_ids) > 0
reimbursement_program = entitlement.program_id.reimbursement_program_id
values.append(
{
"entitlement_id": entitlement.id,
"program_name": entitlement.program_id.name,
"beneficiary_name": entitlement.partner_id.name,
"initial_amount": entitlement.initial_amount,
"is_submitted": is_submitted,
"status": "New" if not is_submitted else entitlement.reimbursement_entitlement_ids.state,
"is_form_mapped": getattr(reimbursement_program, "self_service_portal_form", False)
is not None,
}
)

return request.render(
"g2p_reimbursement_portal.reimbursements_entitlement_view",
{
"entitlements": values,
},
)

@http.route(
["/portal/reimbursement/voucher/<int:_id>"],
type="http",
auth="user",
website=True,
)
def portal_new_submission(self, _id, **kwargs):
self.check_roles("Portal")

current_partner = request.env.user.partner_id

entitlement = request.env["g2p.entitlement"].sudo().browse(_id)
beneficiary = entitlement.partner_id

if entitlement.service_provider_id.id != current_partner.id or entitlement.state != "approved":
raise Forbidden()

# file_size = entitlement.program_id.reimbursement_program_id.file_size_spp

# check if already claimed
if len(entitlement.reimbursement_entitlement_ids) > 0:
return request.redirect(f"/portal/reimbursement/claim/{_id}")

# view = entitlement.program_id.reimbursement_program_id.self_service_portal_form.view_id

return request.render(
"g2p_reimbursement_portal.reimbursement_form_template_view",
{
"entitlement_id": _id,
"current_partner_name": current_partner.given_name.capitalize()
+ ", "
+ current_partner.family_name.capitalize()
if current_partner.given_name and current_partner.family_name
else current_partner.name.capitalize(),
"beneficiary": beneficiary,
# "file_size": file_size,
},
)

@http.route(
["/portal/reimbursement/submit/<int:_id>"],
type="http",
auth="user",
website=True,
csrf=False,
)
def portal_claim_submission(self, _id, **kwargs):
self.check_roles("Portal")

current_partner = request.env.user.partner_id

# TODO: get only issued entitlements

entitlement = request.env["g2p.entitlement"].sudo().browse(_id)
if entitlement.service_provider_id.id != current_partner.id or entitlement.state != "approved":
raise Forbidden()

if request.httprequest.method == "POST":
form_data = kwargs
# check if already claimed
if len(entitlement.reimbursement_entitlement_ids) > 0:
return request.redirect(f"/portal/reimbursement/claim/{_id}")

# TODO: allow resubmission

# TODO: Check if reimbursement program mapped to original program

current_partner_membership = current_partner.program_membership_ids.filtered(
lambda x: x.program_id.id == entitlement.program_id.reimbursement_program_id.id
)
# TODO: Check current partner not part of prog memberships of
# reimbursement program.

supporting_documents_store = (
entitlement.program_id.reimbursement_program_id.supporting_documents_store
)

# TODO: remove all hardcoding in the next lines
received_code = form_data.get("voucher_code", None)
actual_amount = form_data.get("initial_amount", None)

document_details = {}
for key in kwargs:
if isinstance(kwargs[key], FileStorage):
document_details[key] = request.httprequest.files.getlist(key)

supporting_document_files = self.process_documents(
document_details,
supporting_documents_store,
membership=current_partner_membership,
)
if not supporting_document_files:
_logger.warning("Empty/No File received for field %s", "Statement of Account")
supporting_document_file_ids = None
else:
supporting_document_file_ids = []

# saving the multiple document id
for document_id in supporting_document_files:
supporting_document_file_ids.append(document_id.get("document_id", None))

reimbursement_claim = entitlement.submit_reimbursement_claim(
current_partner,
received_code,
supporting_document_file_ids=supporting_document_file_ids
if supporting_document_file_ids
else None,
amount=actual_amount,
)
if reimbursement_claim == (2, None):
_logger.error("Not a valid Voucher Code")
return request.redirect(f"/portal/reimbursement/voucher/{_id}")

else:
# TODO: search and return currently active claim
# TODO: Check whether entitlement.reimbursement_entitlement_ids[0].partner_id is same as current
if len(entitlement.reimbursement_entitlement_ids) == 0:
return request.redirect(f"/portal/reimbursement/entitlement/{_id}")

return request.redirect(f"/portal/reimbursement/claim/{_id}")

@http.route(
["/portal/reimbursement/claim/<int:_id>"],
type="http",
auth="user",
website=True,
)
def portal_post_submission(self, _id, **kwargs):
self.check_roles("Portal")

entitlement = request.env["g2p.entitlement"].sudo().browse(_id)
current_partner = request.env.user.partner_id

reimbursement_claim = (
request.env["g2p.entitlement"]
.sudo()
.search(
[
("partner_id", "=", current_partner.id),
("reimbursement_original_entitlement_id", "=", entitlement.id),
]
)
)

if len(reimbursement_claim) < 1:
return request.redirect(f"/portal/reimbursement/entitlement/{_id}")

return request.render(
"g2p_reimbursement_portal.reimbursement_form_submitted",
{
"entitlement": entitlement.id,
"submission_date": reimbursement_claim.create_date.strftime("%d-%b-%Y"),
"approved_date": reimbursement_claim.date_approved,
"application_id": reimbursement_claim.id,
"application_status": reimbursement_claim.state,
"user": current_partner.given_name.capitalize()
+ " "
+ current_partner.family_name.capitalize()
if current_partner.given_name and current_partner.family_name
else current_partner.name.capitalize(),
},
)

@http.route("/portal/reimbursement/get_voucher_codes", type="http", auth="user", website=True)
def get_voucher_codes(self):
entitlements = (
request.env["g2p.entitlement"]
.sudo()
.search([("service_provider_id", "=", request.env.user.partner_id.id)])
)

voucher_details = []
for entilement in entitlements:
voucher_details.append(
{
"beneficiary_name": entilement.partner_id.name,
"code": entilement.code,
}
)

return json.dumps(voucher_details)

@classmethod
def add_file_to_store(cls, files, store, program_membership=None, tags=None):
if isinstance(files, FileStorage):
files = [
files,
]
file_details = []
for file in files:
if store and file.filename:
if len(file.filename.split(".")) > 1:
supporting_document_ext = "." + file.filename.split(".")[-1]
else:
supporting_document_ext = None
document_file = store.add_file(
file.stream.read(),
extension=supporting_document_ext,
program_membership=program_membership,
tags=tags,
)
document_uuid = document_file.name.split(".")[0]
file_details.append(
{
"document_id": document_file.id,
"document_uuid": document_uuid,
"document_name": document_file.name,
"document_slug": document_file.slug,
"document_url": document_file.url,
}
)
return file_details

def get_field_to_exclude(self, data):
current_partner = request.env.user.partner_id
keys = []
for key in data:
if key in current_partner:
current_partner[key] = data[key]
keys.append(key)

return keys

def process_documents(self, documents, store, membership):
all_file_details = []
for tag, document in documents.items():
all_file_details += self.add_file_to_store(
document, store, program_membership=membership, tags=tag
)
return all_file_details
Loading

0 comments on commit 2210924

Please sign in to comment.