diff --git a/README.md b/README.md index 2a062045..71b937fd 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ addon | version | maintainers | summary [g2p_programs](g2p_programs/) | 17.0.1.2.0 | | OpenG2P Programs [g2p_proxy_means_test](g2p_proxy_means_test/) | 17.0.1.2.0 | | G2P: Proxy Means Test [g2p_social_registry_importer](g2p_social_registry_importer/) | 17.0.1.2.0 | | Import records from Social Registry +[g2p_reimbursement_portal](g2p_reimbursement_portal/) | 17.0.0.0.0 | | G2P Reimbursement Portal [g2p_theme](g2p_theme/) | 17.0.1.2.0 | | OpenG2P Theme diff --git a/g2p_reimbursement_portal/README.rst b/g2p_reimbursement_portal/README.rst new file mode 100644 index 00000000..1411083f --- /dev/null +++ b/g2p_reimbursement_portal/README.rst @@ -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 `_ + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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 `_. + +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 `_ project on GitHub. + +You are welcome to contribute. diff --git a/g2p_reimbursement_portal/__init__.py b/g2p_reimbursement_portal/__init__.py new file mode 100644 index 00000000..bb5acb31 --- /dev/null +++ b/g2p_reimbursement_portal/__init__.py @@ -0,0 +1,3 @@ +# Part of OpenG2P. See LICENSE file for full copyright and licensing details. +from . import models +from . import controllers diff --git a/g2p_reimbursement_portal/__manifest__.py b/g2p_reimbursement_portal/__manifest__.py new file mode 100644 index 00000000..d386b497 --- /dev/null +++ b/g2p_reimbursement_portal/__manifest__.py @@ -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, +} diff --git a/g2p_reimbursement_portal/controllers/__init__.py b/g2p_reimbursement_portal/controllers/__init__.py new file mode 100644 index 00000000..12a7e529 --- /dev/null +++ b/g2p_reimbursement_portal/controllers/__init__.py @@ -0,0 +1 @@ +from . import main diff --git a/g2p_reimbursement_portal/controllers/main.py b/g2p_reimbursement_portal/controllers/main.py new file mode 100644 index 00000000..716296af --- /dev/null +++ b/g2p_reimbursement_portal/controllers/main.py @@ -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/"], + 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/"], + 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/"], + 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 diff --git a/g2p_reimbursement_portal/data/g2p_reimbursement_portal_form_data.xml b/g2p_reimbursement_portal/data/g2p_reimbursement_portal_form_data.xml new file mode 100644 index 00000000..640c07ad --- /dev/null +++ b/g2p_reimbursement_portal/data/g2p_reimbursement_portal_form_data.xml @@ -0,0 +1,16 @@ + + + + apply_for_reimbursement + True + Apply For Reimbursement + + + + g2p.entitlement + + + diff --git a/g2p_reimbursement_portal/models/__init__.py b/g2p_reimbursement_portal/models/__init__.py new file mode 100644 index 00000000..bd190fa8 --- /dev/null +++ b/g2p_reimbursement_portal/models/__init__.py @@ -0,0 +1 @@ +from . import website diff --git a/g2p_reimbursement_portal/models/website.py b/g2p_reimbursement_portal/models/website.py new file mode 100644 index 00000000..4d603502 --- /dev/null +++ b/g2p_reimbursement_portal/models/website.py @@ -0,0 +1,9 @@ +# Part of OpenG2P. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models + + +class WebsitePage(models.Model): + _inherit = "website.page" + + is_portal_form = fields.Boolean(default=False) diff --git a/g2p_reimbursement_portal/pyproject.toml b/g2p_reimbursement_portal/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/g2p_reimbursement_portal/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/g2p_reimbursement_portal/readme/DESCRIPTION.rst b/g2p_reimbursement_portal/readme/DESCRIPTION.rst new file mode 100644 index 00000000..1bb785f9 --- /dev/null +++ b/g2p_reimbursement_portal/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +OpenG2P Reimbursement Portal diff --git a/g2p_reimbursement_portal/static/description/icon.png b/g2p_reimbursement_portal/static/description/icon.png new file mode 100644 index 00000000..5ecb429e Binary files /dev/null and b/g2p_reimbursement_portal/static/description/icon.png differ diff --git a/g2p_reimbursement_portal/static/description/index.html b/g2p_reimbursement_portal/static/description/index.html new file mode 100644 index 00000000..fc51cdcf --- /dev/null +++ b/g2p_reimbursement_portal/static/description/index.html @@ -0,0 +1,415 @@ + + + + + + +G2P Reimbursement Portal + + + +
+

G2P Reimbursement Portal

+ + +

Alpha OpenG2P/openg2p-program

+

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

+
+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub 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.

+

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 project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/g2p_reimbursement_portal/static/src/css/fonts/Inter-Bold.woff b/g2p_reimbursement_portal/static/src/css/fonts/Inter-Bold.woff new file mode 100644 index 00000000..eaf3d4bf Binary files /dev/null and b/g2p_reimbursement_portal/static/src/css/fonts/Inter-Bold.woff differ diff --git a/g2p_reimbursement_portal/static/src/css/fonts/Inter-BoldItalic.woff b/g2p_reimbursement_portal/static/src/css/fonts/Inter-BoldItalic.woff new file mode 100644 index 00000000..32750761 Binary files /dev/null and b/g2p_reimbursement_portal/static/src/css/fonts/Inter-BoldItalic.woff differ diff --git a/g2p_reimbursement_portal/static/src/css/fonts/Inter-ExtraLight.woff b/g2p_reimbursement_portal/static/src/css/fonts/Inter-ExtraLight.woff new file mode 100644 index 00000000..d0de5f39 Binary files /dev/null and b/g2p_reimbursement_portal/static/src/css/fonts/Inter-ExtraLight.woff differ diff --git a/g2p_reimbursement_portal/static/src/css/fonts/Inter-Italic.woff b/g2p_reimbursement_portal/static/src/css/fonts/Inter-Italic.woff new file mode 100644 index 00000000..a806b382 Binary files /dev/null and b/g2p_reimbursement_portal/static/src/css/fonts/Inter-Italic.woff differ diff --git a/g2p_reimbursement_portal/static/src/css/fonts/Inter-Light.woff b/g2p_reimbursement_portal/static/src/css/fonts/Inter-Light.woff new file mode 100644 index 00000000..c496464d Binary files /dev/null and b/g2p_reimbursement_portal/static/src/css/fonts/Inter-Light.woff differ diff --git a/g2p_reimbursement_portal/static/src/css/fonts/Inter-Medium.woff b/g2p_reimbursement_portal/static/src/css/fonts/Inter-Medium.woff new file mode 100644 index 00000000..d546843f Binary files /dev/null and b/g2p_reimbursement_portal/static/src/css/fonts/Inter-Medium.woff differ diff --git a/g2p_reimbursement_portal/static/src/css/fonts/Inter-Regular.woff b/g2p_reimbursement_portal/static/src/css/fonts/Inter-Regular.woff new file mode 100644 index 00000000..62d3a618 Binary files /dev/null and b/g2p_reimbursement_portal/static/src/css/fonts/Inter-Regular.woff differ diff --git a/g2p_reimbursement_portal/static/src/css/fonts/Inter-SemiBold.woff b/g2p_reimbursement_portal/static/src/css/fonts/Inter-SemiBold.woff new file mode 100644 index 00000000..a815f43a Binary files /dev/null and b/g2p_reimbursement_portal/static/src/css/fonts/Inter-SemiBold.woff differ diff --git a/g2p_reimbursement_portal/static/src/css/fonts/Inter-Thin.woff b/g2p_reimbursement_portal/static/src/css/fonts/Inter-Thin.woff new file mode 100644 index 00000000..62bc58cd Binary files /dev/null and b/g2p_reimbursement_portal/static/src/css/fonts/Inter-Thin.woff differ diff --git a/g2p_reimbursement_portal/static/src/css/portal.css b/g2p_reimbursement_portal/static/src/css/portal.css new file mode 100644 index 00000000..bd23bc55 --- /dev/null +++ b/g2p_reimbursement_portal/static/src/css/portal.css @@ -0,0 +1,1275 @@ +.ssp-contact-us { + visibility: collapse; +} + +.ssp-login-body a { + color: #704880; +} + +.ssp-login-box .btn-primary { + background-color: #704880; + border-color: #704880; +} + +.table-container .table-head-container .table-title { + margin-left: 20px; +} + +.table-head-container .search-box .search-text { + font: normal normal normal 14px/17px Inter; +} + +.view-btn { + top: 336px; + left: 1110px; + width: 84px; + height: 30px; + background: #ffffff 0% 0% no-repeat padding-box; + border: 1px solid #494daf; + border-radius: 4px; + text-align: center; + font: normal 12px Inter; + letter-spacing: 0px; + color: #494daf; + opacity: 1; +} + +.apply-button, +.apply-button:focus-visible { + background: #704880 0% 0% no-repeat padding-box; + outline: none !important; +} +.notapplied-button { + left: 811px; + min-width: 84px; + height: 25px; + background: #dce3e8 0% 0% no-repeat padding-box; + border-radius: 4px; + border-collapse: collapse; + text-align: center; + font: normal 12px Inter; + letter-spacing: 0px; + color: #3e5463; + border: none; + + opacity: 1; +} + +.form-template .breadcrumb-item a { + color: #704880; +} + +.s_website_form_input { + width: 100%; +} + +.form-template .s_website_form_input { + border: 1px solid #868686; +} + +.form-template .s_website_form_input:focus-visible { + border: 1px solid #704880 !important; + outline: none !important; +} + +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +input#statement_of_account { + border: 1px dashed #b5b5b5; + height: 115px; +} + +.beneficiary-detail-btn, +.beneficiary-detail-btn:focus-visible { + background: #ffffff 0% 0% no-repeat padding-box; + border: 1px solid #dedede; + border-radius: 6px; + outline: none !important; + width: 192px; + height: 45px; +} + +.beneficiary-btn-heading { + font: normal normal 600 12px/15px Inter; + color: #393939; + margin: 0px; + padding-top: 5px; +} + +.beneficiary-btn-para { + font: normal normal normal 11px/14px Inter; + color: #838383; +} + +.beneficiary-modal-content { + min-width: 536px; + min-height: 345px; + box-shadow: 0px 2px 5px #0000001a; + border-radius: 10px; +} + +.beneficiary-modal-content .beneficiary-value { + font: normal normal 600 13px/16px Inter; + color: #000000; + text-transform: uppercase; +} + +.beneficiary-modal-content .modal-title { + font: normal normal 600 16px/20px Inter; + color: #484848; +} + +.beneficiary-modal-content .modal-footer .modal-cancel-button, +.beneficiary-modal-content .modal-footer .modal-cancel-button:active { + background: #ffffff 0% 0% no-repeat padding-box !important; + border: 1px solid #704880 !important; + color: #704880 !important; + width: 165px; + height: 46px; + font: normal normal 600 14px/17px Inter; +} + +.container-right .modal-discard-button { + background: #704880 0% 0% no-repeat padding-box !important; + font: normal normal 600 14px/17px Inter; + color: #ffffff !important; + border-color: #704880 !important; +} + +.container-right .modal-footer { + padding: 20px; + padding-top: 0px; + justify-content: end; +} + +.btn-primary { + border-color: #704880 !important; +} + +.form-template .form_submit_action, +.form-template .form_submit_action:hover { + background: #704880 0% 0% no-repeat padding-box; + color: #ffffff; + border: #704880; + font: normal normal 600 14px/17px Inter; +} + +.form-template .form_cancel_action, +.container-right .modal-cancel-button, +.form-template .form_cancel_action:hover, +.form-template .container-right .card-footer a { + border: 1px solid #704880 !important; + color: #704880 !important; +} + +#page-buttons button.active { + background: #704880 0% 0% no-repeat padding-box; +} + +#page-buttons button { + color: #704880; +} + +#multiple-file-upload { + position: relative; + height: 115px; + text-align: center; + padding: 20px; + overflow: auto; +} + +#multiple-file-upload .upload-icon { + padding: 10px; +} + +input#statement_of_account { + border: 1px dashed #b5b5b5; + height: 115px; + position: absolute; + content-visibility: hidden; + max-width: 735px; +} + +.file-block { + border-radius: 10px; + margin: 5px; + color: initial; + display: inline-flex; + & > span.name { + padding-right: 10px; + width: max-content; + display: inline-flex; + } +} +.file-delete { + display: flex; + width: 24px; + color: initial; + background-color: #6eb4ff00; + font-size: large; + justify-content: center; + margin-right: 3px; + cursor: pointer; + &:hover { + background-color: rgba(144, 163, 203, 0.2); + border-radius: 10px; + } + & > span { + transform: rotate(45deg); + } +} +.form-template .container-right .card-header .status { + padding-left: 20px; + padding-bottom: 20px; + margin-top: -12px; +} + +.form-template .container-right .card-header .status button { + background: #c7ebd1 0% 0% no-repeat padding-box; + border-radius: 4px; + color: #075e45; + height: 25px; + border: none; + padding-left: 13px; + padding-right: 11px; + font: normal normal 500 12px/15px Inter; +} + +/* card container */ + +.card-container { + display: flex; + justify-content: space-between; + /* margin-left: 139px; */ + width: 1180px; + /* margin-right: 139px; */ + margin-bottom: 33px; +} +.card { + width: 352px; + + background: #ffffff 0% 0% no-repeat padding-box; + box-shadow: 0px 2px 5px #0000001a; + border-radius: 10px; + opacity: 1; +} +.middle-card { + margin-left: 16px; + margin-right: 16px; +} + +.card-heading { + height: 20px; + margin-top: 20px; + margin-left: 20px; + text-align: left; + font: normal 600 16px/20px Inter; + letter-spacing: 0px; + color: #484848; + opacity: 1; +} +.card-foot { + display: flex; + align-items: center; + justify-content: center; + background-color: none; +} + +/* Main content styles */ +.main-container { + background: #f5f9fc 0% 0% no-repeat padding-box; + /* width: 1366px; */ + height: 100%; + display: block; + padding-top: 30px; + padding-bottom: 30px; + opacity: 1; +} + +.table-container { + top: 120px; + /* margin-left: 139px; */ + width: 1180px; + /* margin-right: 139px; */ + margin-bottom: 33px; + padding-bottom: 10px; + background: #ffffff 0% 0% no-repeat padding-box; + box-shadow: 0px 2px 5px #0000001a; + border-radius: 10px; +} +.table-container .table-head-container { + display: flex; + justify-content: space-between; +} +.table-container .table-head-container .table-title { + margin-top: 15px; + margin-left: 25px; + height: 20px; + text-align: left; + font: normal 600 16px/20px Inter; + letter-spacing: 0px; + color: #484848; + opacity: 1; +} + +.table-head-container .search-box { + width: 273px; + height: 40px; + background: #ffffff 0% 0% no-repeat padding-box; + border: 1px solid #c6c6c6; + margin-right: 10px; + border-radius: 6px; + padding: 10px; + opacity: 1; + display: flex; + margin-top: 20px; + justify-content: start; + align-items: center; +} +.table-head-container .search-box .search-text { + border: none; + margin-left: 10px; + font: normal normal normal 14px/17px Inter; +} +.table-head-container .search-box .search-text:focus { + outline: none; + background-color: none; +} +.search-clear-icon { + display: none; + cursor: pointer; +} + +.tables-values-container { + top: 247px; + left: 149px; + width: 1088px; + + mix-blend-mode: normal; + opacity: 1; + width: 100%; + overflow-y: auto; + overflow-x: auto; +} +.tables-values-container table { + width: 100%; +} + +.tables-values-container table thead { + top: 190px; + left: 139px; + height: 52px; + width: 100%; + padding-right: 43px; + padding-left: 20px; + background: #f8f8f8 0% 0% no-repeat padding-box; + opacity: 1; +} + +.tables-values-container table tbody { + padding-left: 20px; + padding-right: 36px; +} + +.tables-values-container table thead tr th { + /* font: normal 600 13px/16px inter; */ + background: #f8f8f8 0% 0% no-repeat padding-box; + text-align: left; + padding-left: 20px; + letter-spacing: 0px; + color: #535353; + opacity: 1; + color: #000; + font-size: 14px; + font-style: normal; + font-weight: 500; + line-height: normal; +} +.table-title { + color: #000; + font-family: Roboto; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; +} + +.tables-values-container table tbody tr td { + height: 16px; + font: normal 13px/16px Inter; + letter-spacing: 0px; + border-bottom: 1px solid #ddd; + padding-left: 20px; + color: #535353; + opacity: 1; + height: 55px; +} + +.tables-values-container .fa-sort { + font-size: 10px; + color: #a2a2a2; +} +table tr th { + cursor: pointer; +} + +td.right-align { + text-align: right; + padding-right: 30px; +} +td .program-name { + width: 202px; + height: 16px; + text-align: left; + font: normal 600 13px/16px Inter; + letter-spacing: 0px; + color: #783e83; + opacity: 1; +} + +.view-button { + top: 336px; + left: 1110px; + width: 50px; + height: 20px; + border: 1px solid #783e83; + border-radius: 4px; + text-align: center; + font-size: 10px; + letter-spacing: 0px; + color: #783e83; + opacity: 1; + background: rgba(120, 62, 131, 0.1); +} + +.no-programs { + height: 150px !important; + vertical-align: middle; + border-bottom: none !important; +} +#allprograms { + border-top: 1px solid #ddd; +} + +/* card container */ + +.card-container { + display: flex; + justify-content: space-between; + /* margin-left: 139px; */ + width: 1180px; + /* margin-right: 139px; */ + margin-bottom: 33px; +} +.card { + width: 352px; + + background: #ffffff 0% 0% no-repeat padding-box; + box-shadow: 0px 2px 5px #0000001a; + border-radius: 10px; + opacity: 1; +} +.middle-card { + margin-left: 16px; + margin-right: 16px; +} + +.card-heading { + height: 20px; + margin-top: 20px; + margin-left: 20px; + text-align: left; + font: normal 600 16px/20px Inter; + letter-spacing: 0px; + color: #484848; + opacity: 1; +} +.card-foot { + display: flex; + align-items: center; + justify-content: center; + background-color: none; +} +.card-block { + padding-left: 0px; +} + +.card-block li { + width: 312px; + height: 78px; + margin-left: 20px; + margin-right: 20px; + background: #ffffff1a 0% 0% no-repeat padding-box; + border: 1px solid #dbdbdb; + border-radius: 6px; + opacity: 1; + display: flex; + justify-content: start; + align-items: center; + margin-bottom: 10px; +} + +.icon-image { + padding: 30px; + background: #6064c71a 0% 0% no-repeat padding-box; + border-radius: 10px; + opacity: 1; + width: 24px; + height: 24px; + margin: 10px; + opacity: 1; +} + +.icon-image img { + width: 22px; + height: 22px; + margin-top: -10px; + margin-left: -10px; + margin-bottom: 20px; + margin-right: 20px; +} + +li div a { + width: 78px; + height: 17px; + text-align: left; + font: normal 600 14px/17px Inter; + letter-spacing: 0px; + color: #484848; + opacity: 1; +} +li div p { + height: 16px; + text-align: left; + font: normal 13px Inter; + letter-spacing: 0px; + color: #484848; + opacity: 1; +} + +.breadcrumb-list { + /* margin-left: 9%; */ + margin-right: 10%; + margin-bottom: 33px; + left: 139px; + height: 17px; + opacity: 1; + padding-left: 0px; +} +.breadcrumb-list .breadcrumb-item a { + width: 40px; + height: 17px; + + text-align: left; + font: normal 600 14px/17px Inter; + letter-spacing: 0px; + color: #783e83 !important; + opacity: 1; +} +.invisible { + display: none; +} +#chartContainer { + width: 220px; + height: 220px; + margin: auto; +} +.breadcrumb-item + .breadcrumb-item::before { + content: " \003E "; + color: black !important; +} +.pagination { + margin-top: 22px; +} + +#search-clear { + display: none; + cursor: pointer; + margin-left: 5px; + padding-right: 25px; +} +#seacrh-text-clear { + display: none; + cursor: pointer; + margin-left: 5px; + padding-right: 25px; +} + +.form-template .o_default_snippet_text { + display: none !important; +} + +.form-template .details { + text-align: left; + font: normal normal 600 22px/26px Inter; + letter-spacing: 0px; + color: #484848; + opacity: 1; + margin-top: 8px; +} + +.form-template .form-layout-breadcrumb { + background-color: #f5f9fc; + padding-left: 0px; + padding-top: 10px; +} + +.form-template .breadcrumb-item { + font: normal normal 600 14px/17px Inter; +} + +.form-template .breadcrumb-item + .breadcrumb-item::before { + content: ">"; + padding: 0px; + padding-right: 19px; + width: 6px; + height: 10px; + color: black !important; +} + +.form-template .breadcrumb-item a { + color: #783e83; + font: normal normal 600 14px/17px Inter; +} + +.form-template .active { + color: #848484; + font: normal normal 600 14px/17px Inter; +} + +.form-template .toast-success-container { + display: block !important; +} + +.form-template .toast-success-message { + background-color: #66ad5a !important; + height: 93px !important; + padding-right: 41px !important; + line-height: 15px; +} + +.form-template .container-left { + background: #ffffff 0% 0% no-repeat padding-box; + box-shadow: 0px 2px 5px #0000001a; + border-radius: 10px; + opacity: 1; +} + +.form-template .container-right { + background: #ffffff 0% 0% no-repeat padding-box; + box-shadow: 0px 2px 5px #0000001a; + border-radius: 10px; + opacity: 1; +} + +.form-template .card-header { + background-color: #ffffff; +} + +.form-template .form-card-header { + padding-left: 0px; +} + +.form-template .form-heading { + text-align: left; + font: normal normal 600 16px/20px Inter; + letter-spacing: 0px; + color: #000; + opacity: 1; + padding-left: 20px; + font-size: 16px; + font-weight: 500; + padding-top: 18px; + padding-right: 20px; + padding-bottom: 3px; +} + +.form-template .form-description { + text-align: left; + font: normal normal 500 13px/16px Inter; + letter-spacing: 0px; + color: #959595; + opacity: 1; + margin-bottom: 0px; + font-size: 13px; + padding-left: 20px; + padding-bottom: 18px; + padding-right: 20px; +} + +.form-template .s_website_form { + padding: 0px !important; + margin-bottom: 5px; +} + +.form-template .s_website_form_label_content { + text-align: left; + font: normal normal 500 14px/17px Inter; + letter-spacing: 0px; + color: black !important; +} + +.form-template .s_website_form_label { + margin-bottom: 7px; +} + +.form-template .s_website_form_input { + font: normal normal normal 14px/17px Inter; + background: #ffffff 0% 0% no-repeat padding-box; + border: 1px solid #e3e3e3; + border-radius: 6px; + opacity: 1; + height: 48px; + box-shadow: none; + padding-left: 11px; + padding-top: 16px; + padding-bottom: 12px; + padding-right: 11px; +} + +.form-template .s_website_form_field { + font: normal normal normal 14px/17px Inter; + padding-left: 20px; + padding-right: 20px; + padding-top: 16px !important; + padding-bottom: 14px !important; + margin-left: 30px; +} + +.s_website_form_mark { + color: #d32d2d; +} + +.form-template .s_website_form_multiple { + min-height: 48px; +} + +.form-template .s_website_form_multiple div { + padding-bottom: 10px; + padding-top: 10px; +} + +.form-template .s_website_form_multiple div .form-check { + padding: 0px; +} + +.form-template .form-check .form-check-input { + height: 22px; + width: 22px; + accent-color: #783e83; + fill: #783e83; + border-radius: 16px; + border: 1px solid rgba(120, 62, 131, 0.5); + box-shadow: 0px 2px 8px 0px rgba(120, 62, 131, 0.2); +} + +.form-template .form-check .form-check-input:focus-visible { + outline: none; +} + +.form-template .s_website_form_check_label { + padding-left: 25px; + font: normal normal normal 14px/17px Inter; +} + +.form-template .s_website_form_submit { + display: none; +} + +.form-template .input-field-error-message, +.input-field-validation-message { + color: #d52929; + font: normal normal normal 14px/17px Inter; +} + +.form-template .action-heading { + text-align: left; + font: normal normal 600 16px/20px Inter; + letter-spacing: 0px; + color: #484848; + opacity: 1; + padding-left: 20px; + padding-right: 20px; + padding-top: 25px; + margin: 0px; + padding-bottom: 18px; +} + +.form-template .action-description { + text-align: left; + letter-spacing: 0px; + opacity: 1; + padding-left: 20px; + padding-bottom: 34px; + margin: 0px; + padding-right: 20px; +} + +.form-template .form_submit_action { + background: #783e83 0% 0% no-repeat padding-box; + border-radius: 6px; + opacity: 1; + font: normal normal 600 14px/17px Inter; + height: 54px; +} + +.form-template .form_cancel_action { + background: #ffffff 0% 0% no-repeat padding-box; + color: #783e83; + border: 1px solid #783e83; + border-radius: 6px; + opacity: 1; + font: normal normal 600 14px/17px Inter; + height: 54px; + margin-top: 14px; +} + +.form-template .form_submit_action:focus { + box-shadow: none !important; +} + +.form-template .form_cancel_action:focus { + box-shadow: none !important; +} + +.form-template .form_cancel_action:hover { + color: #783e83; + background: #fcfcff 0% 0% no-repeat padding-box; + border: 1px solid #6c70cb; + border-radius: 6px; + opacity: 1; +} + +.form-template .form_submit_action:hover { + color: #fffffe; + background: #6569c7 0% 0% no-repeat padding-box; + border-radius: 6px; + opacity: 1; +} + +.form-template .form_cancel_action:active { + color: #783e83 !important; + background: #fcfcff 0% 0% no-repeat padding-box !important; + border: 1px solid #6c70cb !important; + border-radius: 6px !important; + opacity: 1 !important; +} + +.form-template .form_submit_action:active { + color: #fffffe !important; + background: #6569c7 0% 0% no-repeat padding-box !important; + border-radius: 6px !important; + opacity: 1 !important; +} + +.container-right .modal-dialog-centered { + width: fit-content; +} + +.container-right .modal-content { + background: #ffffff 0% 0% no-repeat padding-box; + box-shadow: 0px 2px 5px #0000001a; + border-radius: 10px; + opacity: 1; + width: 352px; + height: 177px; +} + +.container-right .modal-header { + text-align: left; + font: normal normal 600 16px/20px Inter; + letter-spacing: 0px; + color: #484848; + opacity: 1; + border: none; + padding: 25px !important; + padding-bottom: 0px !important; +} + +.container-right .modal-title { + font: normal normal 600 16px/20px Inter; + color: #484848; +} + +.container-right .modal-body { + text-align: left; + font: normal normal normal 14px/17px Inter; + letter-spacing: 0px; + color: #484848; + opacity: 1; + padding: 25px; + padding-top: 8px; + overflow: hidden; +} + +.container-right .modal-body p { + margin: 0px; + font-size: 14px; + color: #484848; +} + +.container-right .modal-footer { + border: none; + padding: 25px; + padding-top: 0px; + justify-content: normal; +} + +.container-right .modal-footer button { + width: 123px; + height: 40px; +} + +.container-right .modal-discard-button { + background: #783e83 0% 0% no-repeat padding-box; + border-radius: 6px; + opacity: 1; + text-align: center; + font: normal normal 600 14px/17px Inter; + letter-spacing: 0px; + color: #ffffff; + font-size: 14px; + margin-right: 5px !important; +} + +.container-right .modal-cancel-button { + background: #ffffff 0% 0% no-repeat padding-box; + border: 1px solid #783e83; + border-radius: 6px; + opacity: 1; + text-align: center; + font: normal normal 600 14px/17px Inter; + letter-spacing: 0px; + color: #783e83; + font-size: 14px; + margin-left: 5px !important; +} + +.container-right .modal-discard-button:focus { + box-shadow: none !important; +} + +.container-right .modal-cancel-button:focus { + box-shadow: none !important; +} + +.container-right .modal-discard-button:hover { + background: #6569c7 0% 0% no-repeat padding-box; + border-radius: 6px; + opacity: 1; +} + +.container-right .modal-cancel-button:hover { + background: #fcfcff 0% 0% no-repeat padding-box; + border: 1px solid #6c70cb; + border-radius: 6px; + opacity: 1; + color: #783e83; +} + +.container-right .modal-discard-button:active { + background: #783e83 0% 0% no-repeat padding-box !important; + border-radius: 6px !important; + opacity: 1 !important; + text-align: center !important; + font: normal normal 600 14px/17px Inter !important; + letter-spacing: 0px !important; + color: #ffffff !important; +} + +.container-right .modal-cancel-button:active { + background: #ffffff 0% 0% no-repeat padding-box !important; + border: 1px solid #783e83 !important; + border-radius: 6px !important; + opacity: 1 !important; + text-align: center !important; + font: normal normal 600 14px/17px Inter !important; + letter-spacing: 0px !important; + color: #783e83 !important; +} + +.form-template .container-right .card-header .form-status { + padding-left: 20px; + padding-bottom: 20px; + margin-top: -12px; +} + +.form-template .container-right .card-header .form-status button { + background: #faf6cf 0% 0% no-repeat padding-box; + border-radius: 4px; + color: #3c5160; + height: 25px; + border: none; + padding-left: 13px; + padding-right: 11px; + font: normal normal 500 12px/15px Inter; +} + +.form-template .container-right .card-header .form-status button:focus, +.form-template .container-right .card-header .form-status button:focus-visible { + outline: none !important; +} + +.form-template .container-right .form-application-id { + margin-bottom: 20px; +} + +.form-template .container-right p { + margin: 0px; + color: #777777; + font: normal normal normal 13px/16px Inter; +} + +.form-template .container-right b { + font: normal normal bold 14px/17px Inter; +} + +.form-template .container-right .card-footer, +.form-template .container-right .card-footer a:hover { + background: none; +} + +.form-template .container-right .card-footer a, +.form-template .container-right .card-footer a:active { + border: 1px solid #783e83 !important; + color: #783e83 !important; + font: normal normal 600 14px/17px Inter !important; + height: 54px !important; + background: none !important; + padding-top: 19px; +} + +.form-template .container-right .card-footer a:focus { + box-shadow: none !important; +} + +.form-template .container-right .card-footer a:focus-visible { + outline: none !important; +} + +.form-template .container-left .user-name { + font: normal normal 500 17px/20px Inter; + color: #333333; +} + +.form-template .container-left .thank-you-msg { + font: normal normal normal 15px/23px Inter; + letter-spacing: 0px; + color: #333333; + opacity: 1; + margin: 0px; +} + +.apply-button { + width: 84px; + height: 30px; + border: none; + background: #783e83 0% 0% no-repeat padding-box; + border-radius: 4px; + text-align: center; + font: normal 12px Inter; + letter-spacing: 0px; + color: #ffffff; + + opacity: 1; +} + +.submit-button { + left: 811px; + min-width: 84px; + height: 25px; + + background: #faf6cf 0% 0% no-repeat padding-box; + border-radius: 4px; + border-collapse: collapse; + text-align: center; + font: normal 12px Inter; + letter-spacing: 0px; + color: #3c5160; + border: none; + opacity: 1; +} + +#page-buttons { + display: flex; + justify-content: center; + gap: 35px; +} + +#page-buttons button { + border: none; + background-color: transparent; + color: black; + font-size: 16px; + cursor: pointer; + outline: none; + padding: 5px; +} + +#page-buttons button.active { + top: 736px; + left: 563px; + width: 32px; + height: 32px; + color: #fffffe; + background: #783e83 0% 0% no-repeat padding-box; + border-radius: 6px; + opacity: 1; +} + +.next-button { + border: 1px solid black; + padding: 5px 10px; +} + +#toast-container { + display: none; + position: fixed; + top: 110px; + right: 30px; + width: 304px; + height: 48px; + z-index: 1100; +} + +#toast-message { + background-color: #de514c; + color: #ffffff; + padding: 10px; + border-radius: 5px; + padding-left: 20px; + padding-top: 16px; + padding-bottom: 17px; + font: normal normal 600 12px/15px Inter; +} + +#toast-close-btn { + position: absolute; + top: 0px; + right: 0px; + outline: none; + background: transparent; + border: none; + color: #ffffff; + cursor: pointer; + padding: 0px; + padding-right: 20px; + padding-top: 10px; +} + +#toast-close-btn img { + width: 11px; + height: 11px; +} + +.form-template .toast-success-container { + display: block !important; +} + +.form-template .toast-success-message { + background-color: #66ad5a !important; + height: 93px !important; + padding-right: 41px !important; + line-height: 15px; +} + +.form-template .container-left { + background: #ffffff 0% 0% no-repeat padding-box; + box-shadow: 0px 2px 5px #0000001a; + border-radius: 10px; + opacity: 1; +} + +.form-template .container-right { + background: #ffffff 0% 0% no-repeat padding-box; + box-shadow: 0px 2px 5px #0000001a; + border-radius: 10px; + opacity: 1; +} + +.form-template .card-header { + background-color: #ffffff; +} + +.form-template .form-card-header { + padding-left: 0px; +} + +.form-template .form-heading { + text-align: left; + font: normal normal 600 16px/20px Inter; + letter-spacing: 0px; + color: #484848; + opacity: 1; + padding-left: 20px; + font-size: 16px; + padding-top: 18px; + padding-right: 20px; + padding-bottom: 3px; +} + +.form-template .form-description { + text-align: left; + font: normal normal 500 13px/16px Inter; + letter-spacing: 0px; + color: #959595; + opacity: 1; + margin-bottom: 0px; + font-size: 13px; + padding-left: 20px; + padding-bottom: 18px; + padding-right: 20px; +} + +.form-template .s_website_form { + padding: 0px !important; + margin-bottom: 5px; +} + +.note { + padding-top: 15px; +} + +.note .container { + padding-left: 20px; + padding-right: 20px; +} + +.mandatory-fields-note { + background: #faf6cf 0% 0% no-repeat padding-box; + border-radius: 4px; + opacity: 1; + font: normal normal 500 13px/16px Inter; + color: #585211; + padding-left: 8px; + padding-top: 5px; + padding-bottom: 5px; + padding-right: 8px; + margin-bottom: 9px; +} + +.form-template .container-right .card-header .form-status { + padding-left: 20px; + padding-bottom: 20px; + margin-top: -12px; +} + +.form-template .container-right .card-header .form-status button { + background: #faf6cf 0% 0% no-repeat padding-box; + border-radius: 4px; + color: #3c5160; + height: 25px; + border: none; + padding-left: 13px; + padding-right: 11px; + font: normal normal 500 12px/15px Inter; +} + +.form-template .container-right .card-header .form-status button:focus, +.form-template .container-right .card-header .form-status button:focus-visible { + outline: none !important; +} diff --git a/g2p_reimbursement_portal/static/src/img/close_icon@2x.png b/g2p_reimbursement_portal/static/src/img/close_icon@2x.png new file mode 100644 index 00000000..01907159 Binary files /dev/null and b/g2p_reimbursement_portal/static/src/img/close_icon@2x.png differ diff --git a/g2p_reimbursement_portal/static/src/img/flag_en.png b/g2p_reimbursement_portal/static/src/img/flag_en.png new file mode 100644 index 00000000..5fc1b1a8 Binary files /dev/null and b/g2p_reimbursement_portal/static/src/img/flag_en.png differ diff --git a/g2p_reimbursement_portal/static/src/img/flag_fr.png b/g2p_reimbursement_portal/static/src/img/flag_fr.png new file mode 100644 index 00000000..d23d639d Binary files /dev/null and b/g2p_reimbursement_portal/static/src/img/flag_fr.png differ diff --git a/g2p_reimbursement_portal/static/src/img/flag_ph.png b/g2p_reimbursement_portal/static/src/img/flag_ph.png new file mode 100644 index 00000000..585210d4 Binary files /dev/null and b/g2p_reimbursement_portal/static/src/img/flag_ph.png differ diff --git a/g2p_reimbursement_portal/static/src/img/logo.png b/g2p_reimbursement_portal/static/src/img/logo.png new file mode 100644 index 00000000..390c2ef1 Binary files /dev/null and b/g2p_reimbursement_portal/static/src/img/logo.png differ diff --git a/g2p_reimbursement_portal/static/src/img/logo@2x.png b/g2p_reimbursement_portal/static/src/img/logo@2x.png new file mode 100644 index 00000000..b4f01a61 Binary files /dev/null and b/g2p_reimbursement_portal/static/src/img/logo@2x.png differ diff --git a/g2p_reimbursement_portal/static/src/img/page_under_construction.png b/g2p_reimbursement_portal/static/src/img/page_under_construction.png new file mode 100644 index 00000000..ddc1f995 Binary files /dev/null and b/g2p_reimbursement_portal/static/src/img/page_under_construction.png differ diff --git a/g2p_reimbursement_portal/static/src/img/person_filled_FILL0_wght400_GRAD0_opsz48.png b/g2p_reimbursement_portal/static/src/img/person_filled_FILL0_wght400_GRAD0_opsz48.png new file mode 100644 index 00000000..7c096bfe Binary files /dev/null and b/g2p_reimbursement_portal/static/src/img/person_filled_FILL0_wght400_GRAD0_opsz48.png differ diff --git a/g2p_reimbursement_portal/static/src/js/form_action.js b/g2p_reimbursement_portal/static/src/js/form_action.js new file mode 100644 index 00000000..40a29b72 --- /dev/null +++ b/g2p_reimbursement_portal/static/src/js/form_action.js @@ -0,0 +1,89 @@ +var voucherDetails = []; + +fetch("/portal/reimbursement/get_voucher_codes") + .then(function (response) { + if (response.ok) { + return response.json(); + } + }) + .then(function (data) { + if (data) { + voucherDetails = data; + } + }); + +// eslint-disable-next-line no-unused-vars +function showToast(message) { + const toast_message = document.querySelector("#toast-message"); + toast_message.textContent = message; + const toast_container = document.querySelector("#toast-container"); + toast_container.style.display = "block"; +} + +// eslint-disable-next-line no-unused-vars +function hideToast() { + const toast_container = document.querySelector("#toast-container"); + toast_container.style.display = "none"; +} + +// eslint-disable-next-line no-unused-vars +function hideToastSuccessMsg() { + const toast_msg = $(".toast-success-message")[0]; + toast_msg.style.display = "none"; +} + +// eslint-disable-next-line no-unused-vars,complexity +function reimbursementFormSubmitAction() { + var formContainer = $(".s_website_form"); + var programForm = formContainer.find("form"); + var voucherInputField = $("[name='voucher_code']"); + var isValid = true; + var program_id = $("#program_submit_id"); + var beneficiayName = program_id[0].getAttribute("beneficiary"); + + programForm[0].action = `/portal/reimbursement/submit/${program_id[0].getAttribute("program")}`; + + var modal = $("#SubmitModal"); + var requiredFields = $(".s_website_form_required"); + var inputFields = requiredFields.find("input"); + + for (let i = 0; i < requiredFields.length; i++) { + inputFields[i].style.borderColor = "#E3E3E3"; + if (inputFields[i].value === "") { + isValid = false; + modal[0].click(close); + // eslint-disable-next-line no-undef + showToast("Please update all mandatory fields."); + inputFields[i].style.borderColor = "#DE514C"; + } else { + for (let j = 0; j < voucherDetails.length; j++) { + if ( + voucherInputField[0] && + voucherDetails[j].beneficiary_name === beneficiayName && + voucherDetails[j].code === voucherInputField[0].value + ) { + isValid = true; + break; + } else if (voucherInputField[0]) { + isValid = false; + modal[0].click(close); + // eslint-disable-next-line no-undef + showToast("Please enter a valid voucher code."); + voucherInputField[0].style.borderColor = "#DE514C"; + } else { + isValid = false; + modal[0].click(close); + // eslint-disable-next-line no-undef + showToast( + "Voucher code or Actual Amount fields are not correctly mapped. Please re-check your form or Contact your Administrator." + ); + } + } + } + } + + if (isValid) { + // eslint-disable-next-line no-undef + programForm[0].submit(); + } +} diff --git a/g2p_reimbursement_portal/static/src/js/reim_form_editor.js b/g2p_reimbursement_portal/static/src/js/reim_form_editor.js new file mode 100644 index 00000000..1c7ec9ca --- /dev/null +++ b/g2p_reimbursement_portal/static/src/js/reim_form_editor.js @@ -0,0 +1,32 @@ +/** @odoo-module **/ +import FormEditorRegistry from "@website/js/form_editor_registry"; + +FormEditorRegistry.add("apply_for_reimbursement", { + formFields: [ + { + type: "char", + custom: false, + required: true, + placeholder: "Enter Voucher Code", + fillWith: "code", + name: "code", + string: "Voucher Code", + }, + { + type: "float", + custom: false, + required: true, + placeholder: "Enter Amount", + fillWith: "initial_amount", + name: "initial_amount", + string: "Actual Amount", + }, + { + type: "binary", + custom: true, + required: true, + name: "invoice", + string: "Invoice", + }, + ], +}); diff --git a/g2p_reimbursement_portal/static/src/js/table_pagination_and_row.js b/g2p_reimbursement_portal/static/src/js/table_pagination_and_row.js new file mode 100644 index 00000000..4ca07cbf --- /dev/null +++ b/g2p_reimbursement_portal/static/src/js/table_pagination_and_row.js @@ -0,0 +1,186 @@ +const alltable = document.getElementById("newreimbursements"); +const allheadercells = alltable.querySelectorAll("th"); +const allRows = Array.from(alltable.querySelectorAll("tbody tr")); +const tbody = alltable.getElementsByTagName("tbody"); +const totalRow = tbody[0].children.length; +const itemsPerPage = 7; +let currentPage = 1; + +function addTableSrNo() { + for (let i = 0; i < totalRow; i++) { + tbody[0].children[i].firstElementChild.innerText = i + 1; + } +} + +addTableSrNo(); +let filteredRows = []; +function showPage(page) { + const startIndex = (page - 1) * itemsPerPage; + const endIndex = startIndex + itemsPerPage; + const rows = filteredRows.slice(startIndex, endIndex); + // Hide all rows + allRows.forEach((row) => (row.style.display = "none")); + // Show rows for current page + rows.forEach((row) => (row.style.display = "")); +} +function updatePaginationButtons() { + const pageButtonsContainer = document.getElementById("page-buttons"); + const buttons = pageButtonsContainer.querySelectorAll("button"); + buttons.forEach((button) => { + button.classList.remove("active"); + if (Number(button.textContent) === currentPage) { + button.classList.add("active"); + } + }); + + const prevButton = pageButtonsContainer.querySelector("button:first-child"); + const nextButton = pageButtonsContainer.querySelector(".next-button"); + + prevButton.disabled = currentPage === 1; + nextButton.disabled = currentPage === Math.ceil(filteredRows.length / itemsPerPage); +} + +function applySearchFilter(searchValue) { + filteredRows = allRows.filter((row) => { + const cellValue1 = row.cells[2].innerText; + const cellValue2 = row.cells[3].innerText.toLowerCase(); + return cellValue1.includes(searchValue) || cellValue2.includes(searchValue); + }); +} + +function renderPageButtons() { + const totalPages = Math.ceil(filteredRows.length / itemsPerPage); + const pageButtonsContainer = document.getElementById("page-buttons"); + pageButtonsContainer.innerHTML = ""; + + // Add previous page button + const prevButton = document.createElement("button"); + prevButton.innerHTML = ''; + + // Add next page button + const nextButton = document.createElement("button"); + nextButton.innerHTML = ''; + + // Angle bracket for left arrow + prevButton.addEventListener("click", function () { + if (currentPage > 1) { + currentPage--; + showPage(currentPage); + updatePaginationButtons(); + } + }); + pageButtonsContainer.appendChild(prevButton); + + // Add page buttons + for (let i = 1; i <= totalPages; i++) { + const button = document.createElement("button"); + button.textContent = i; + if (i === currentPage) { + button.classList.add("active"); + } + + button.addEventListener("click", function () { + currentPage = i; + showPage(currentPage); + updatePaginationButtons(); + }); + + pageButtonsContainer.appendChild(button); + } + + // Angular bracket for right arrow + nextButton.classList.add("next-button"); + nextButton.addEventListener("click", function () { + if (currentPage < totalPages) { + currentPage++; + showPage(currentPage); + updatePaginationButtons(); + } + }); + pageButtonsContainer.appendChild(nextButton); + + updatePaginationButtons(); +} +function compareCellValues(a, b, columnIndex) { + const aCellValue = a.cells[columnIndex].textContent.trim().replace(/,/g, ""); + const bCellValue = b.cells[columnIndex].textContent.trim().replace(/,/g, ""); + const aNumber = parseFloat(aCellValue); + const bNumber = parseFloat(bCellValue); + + if (!isNaN(aNumber) && !isNaN(bNumber)) { + return aNumber - bNumber; + } + return aCellValue.localeCompare(bCellValue); +} + +allheadercells.forEach(function (th) { + // Default sort order + let sortOrder = "asc"; + th.addEventListener("click", function () { + const columnIndex = th.cellIndex; + allRows.sort(function (a, b) { + let comparison = compareCellValues(a, b, columnIndex); + + if (sortOrder === "desc") { + comparison *= -1; + } + return comparison; + }); + + sortOrder = sortOrder === "asc" ? "desc" : "asc"; + allRows.forEach((row) => { + alltable.tBodies[0].appendChild(row); + }); + allRows.forEach((row, index) => { + const firstCell = row.cells[0]; + firstCell.innerText = index + 1; + }); + currentPage = 1; + showPage(currentPage); + renderPageButtons(); + }); +}); + +const searchInputText = document.getElementById("search-text"); +const searchClearText = document.getElementById("search-text-clear"); +searchClearText.style.display = "none"; + +function handleSearch() { + var searchValue = searchInputText.value; + + if (typeof searchValue === "string") { + searchValue = searchValue.toLowerCase(); + } + + if (searchValue) { + applySearchFilter(searchValue); + currentPage = 1; + showPage(currentPage); + renderPageButtons(); + } else { + filteredRows = allRows; + currentPage = 1; + showPage(currentPage); + renderPageButtons(); + } + + searchClearText.style.display = searchValue ? "block" : "none"; +} + +searchInputText.addEventListener("input", handleSearch); + +searchClearText.addEventListener("click", function () { + searchInputText.value = ""; + handleSearch(); +}); + +document.addEventListener("click", function (event) { + if (event.target !== searchInputText && event.target !== searchClearText) { + searchClearText.style.display = searchInputText.value ? "block" : "none"; + } +}); + +// Initial setup +filteredRows = allRows; +showPage(currentPage); +renderPageButtons(); diff --git a/g2p_reimbursement_portal/views/base.xml b/g2p_reimbursement_portal/views/base.xml new file mode 100644 index 00000000..7d032028 --- /dev/null +++ b/g2p_reimbursement_portal/views/base.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/g2p_reimbursement_portal/views/g2p_portal_dashboard.xml b/g2p_reimbursement_portal/views/g2p_portal_dashboard.xml new file mode 100644 index 00000000..ddb603cd --- /dev/null +++ b/g2p_reimbursement_portal/views/g2p_portal_dashboard.xml @@ -0,0 +1,36 @@ + + + + diff --git a/g2p_reimbursement_portal/views/g2p_portal_form_submitted.xml b/g2p_reimbursement_portal/views/g2p_portal_form_submitted.xml new file mode 100644 index 00000000..cc850328 --- /dev/null +++ b/g2p_reimbursement_portal/views/g2p_portal_form_submitted.xml @@ -0,0 +1,128 @@ + + + + diff --git a/g2p_reimbursement_portal/views/g2p_portal_form_template.xml b/g2p_reimbursement_portal/views/g2p_portal_form_template.xml new file mode 100644 index 00000000..e5da60d7 --- /dev/null +++ b/g2p_reimbursement_portal/views/g2p_portal_form_template.xml @@ -0,0 +1,452 @@ + + +