Skip to content

Commit

Permalink
24695 - EFT add cas supplier site - backend changes (bcgov#1848)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jxio authored Dec 5, 2024
1 parent 6555234 commit 10eeaa9
Show file tree
Hide file tree
Showing 20 changed files with 469 additions and 223 deletions.
28 changes: 23 additions & 5 deletions jobs/payment-jobs/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion jobs/payment-jobs/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ readme = "README.md"

[tool.poetry.dependencies]
python = "^3.12"
pay-api = {git = "https://github.com/bcgov/sbc-pay.git", branch = "main", subdirectory = "pay-api"}
pay-api = {git = "https://github.com/Jxio/sbc-pay.git", branch = "24695", subdirectory = "pay-api"}
flask = "^3.0.2"
flask-sqlalchemy = "^3.1.1"
sqlalchemy = "^2.0.28"
Expand Down
31 changes: 23 additions & 8 deletions jobs/payment-jobs/tasks/ap_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
from sqlalchemy import Date, cast

from tasks.common.cgi_ap import CgiAP
from tasks.common.dataclasses import APLine
from tasks.common.dataclasses import APHeader, APLine, APSupplier


class ApTask(CgiAP):
Expand Down Expand Up @@ -130,20 +130,26 @@ def _create_eft_refund_file(cls):
current_app.logger.info(
f"Creating refund for EFT Refund {eft_refund.id}, Amount {eft_refund.refund_amount}."
)
ap_content = f"{ap_content}{cls.get_ap_header(
eft_refund.refund_amount, eft_refund.id, eft_refund.created_on, eft_refund.cas_supplier_number)}"
ap_header = APHeader(
total=eft_refund.refund_amount,
invoice_number=eft_refund.id,
invoice_date=eft_refund.created_on,
ap_supplier=APSupplier(eft_refund.cas_supplier_number, eft_refund.cas_supplier_site)
)
ap_content = f"{ap_content}{cls.get_ap_header(ap_header)}"
ap_line = APLine(
total=eft_refund.refund_amount,
invoice_number=eft_refund.id,
line_number=line_count_total + 1,
ap_supplier=APSupplier(eft_refund.cas_supplier_number, eft_refund.cas_supplier_site)
)
ap_content = f"{ap_content}{cls.get_ap_invoice_line(ap_line, eft_refund.cas_supplier_number)}"
ap_content = f"{ap_content}{cls.get_ap_invoice_line(ap_line)}"
line_count_total += 2
if ap_comment := cls.get_eft_ap_comment(
eft_refund.comment,
eft_refund.id,
eft_refund.short_name_id,
eft_refund.cas_supplier_number,
supplier_line=APSupplier(eft_refund.cas_supplier_number, eft_refund.cas_supplier_site)
):
ap_content = f"{ap_content}{ap_comment:<40}"
line_count_total += 1
Expand Down Expand Up @@ -185,8 +191,12 @@ def _create_routing_slip_refund_file(
for rs in routing_slips:
current_app.logger.info(f"Creating refund for {rs.number}, Amount {rs.refund_amount}.")
refund: RefundModel = RefundModel.find_by_routing_slip_id(rs.id)
ap_content = f"{ap_content}{cls.get_ap_header(rs.refund_amount, rs.number,
datetime.now(tz=timezone.utc))}"
ap_header = APHeader(
total=rs.refund_amount,
invoice_number=rs.number,
invoice_date=datetime.now(tz=timezone.utc)
)
ap_content = f"{ap_content}{cls.get_ap_header(ap_header)}"
ap_line = APLine(total=rs.refund_amount, invoice_number=rs.number, line_number=1)
ap_content = f"{ap_content}{cls.get_ap_invoice_line(ap_line)}"
ap_content = f"{ap_content}{cls.get_ap_address(refund.details, rs.number)}"
Expand Down Expand Up @@ -298,7 +308,12 @@ def _create_non_gov_disbursement_file(cls): # pylint:disable=too-many-locals
batch_total += disbursement_invoice_total
if disbursement_invoice_total == 0:
continue
ap_content = f"{ap_content}{cls.get_ap_header(disbursement_invoice_total, inv.id, inv.created_on)}"
ap_header = APHeader(
total=disbursement_invoice_total,
invoice_number=inv.id,
invoice_date=inv.created_on
)
ap_content = f"{ap_content}{cls.get_ap_header(ap_header)}"
control_total += 1
line_number: int = 0
for line_item in inv.payment_line_items:
Expand Down
35 changes: 19 additions & 16 deletions jobs/payment-jobs/tasks/common/cgi_ap.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from pay_api.utils.enums import DisbursementMethod, EjvFileType
from pay_api.utils.util import get_fiscal_year

from tasks.common.dataclasses import APLine
from tasks.common.dataclasses import APHeader, APLine, APSupplier

from .cgi_ejv import CgiEjv

Expand Down Expand Up @@ -48,42 +48,45 @@ def get_batch_trailer(cls, batch_number, batch_total, batch_type: str = "AP", co
)

@classmethod
def get_ap_header(cls, total, invoice_number, invoice_date, supplier_number: str = None):
def get_ap_header(cls, ap_header: APHeader):
"""Get AP Invoice Header string."""
invoice_type = "ST"
remit_code = f"{current_app.config.get('CGI_AP_REMITTANCE_CODE'):<4}"
currency = "CAD"
effective_date = cls._get_date(datetime.now(tz=timezone.utc))
invoice_date = cls._get_date(invoice_date)
oracle_invoice_batch_name = cls._get_oracle_invoice_batch_name(invoice_number)
invoice_date = cls._get_date(ap_header.invoice_date)
oracle_invoice_batch_name = cls._get_oracle_invoice_batch_name(ap_header.invoice_number)
disbursement_method = (
DisbursementMethod.CHEQUE.value if cls.ap_type == EjvFileType.REFUND else DisbursementMethod.EFT.value
)
term = f"{cls.EMPTY:<50}" if cls.ap_type == EjvFileType.REFUND else f"Immediate{cls.EMPTY:<41}"

ap_header = (
f"{cls._feeder_number()}APIH{cls.DELIMITER}{cls._supplier_number(supplier_number)}"
f"{cls._supplier_location()}{invoice_number:<50}{cls._po_number()}{invoice_type}{invoice_date}"
f"GEN {disbursement_method} N{remit_code}{cls.format_amount(total)}{currency}{effective_date}"
f"{cls._feeder_number()}APIH{cls.DELIMITER}{cls._supplier_number(ap_header.ap_supplier.supplier_number)}"
f"{cls._supplier_location(ap_header.ap_supplier.supplier_site)}"
f"{ap_header.invoice_number:<50}{cls._po_number()}{invoice_type}{invoice_date}"
f"GEN {disbursement_method} N{remit_code}{cls.format_amount(ap_header.total)}{currency}{effective_date}"
f"{term}{cls.EMPTY:<60}{cls.EMPTY:<8}{cls.EMPTY:<8}"
f"{oracle_invoice_batch_name:<30}{cls.EMPTY:<9}Y{cls.EMPTY:<110}{cls.DELIMITER}{os.linesep}"
)
return ap_header

@classmethod
def get_ap_invoice_line(cls, ap_line: APLine, supplier_number: str = None):
def get_ap_invoice_line(cls, ap_line: APLine):
"""Get AP Invoice Line string."""
commit_line_number = f"{cls.EMPTY:<4}"
# Pad Zeros to four digits. EG. 0001
line_number = f"{ap_line.line_number:04}"
effective_date = cls._get_date(datetime.now(tz=timezone.utc))
line_code = cls._get_line_code(ap_line)
ap_line = (
f"{cls._feeder_number()}APIL{cls.DELIMITER}{cls._supplier_number(supplier_number)}"
f"{cls._supplier_location()}{ap_line.invoice_number:<50}{line_number}{commit_line_number}"
f"{cls._feeder_number()}APIL{cls.DELIMITER}{cls._supplier_number(ap_line.ap_supplier.supplier_number)}"
f"{cls._supplier_location(ap_line.ap_supplier.supplier_site)}{ap_line.invoice_number:<50}"
f"{line_number}{commit_line_number}"
f"{cls.format_amount(ap_line.total)}{line_code}{cls._distribution(ap_line.distribution)}{cls.EMPTY:<55}"
f"{effective_date}{cls.EMPTY:<10}{cls.EMPTY:<15}{cls.EMPTY:<15}{cls.EMPTY:<15}{cls.EMPTY:<15}"
f"{cls.EMPTY:<20}{cls.EMPTY:<4}{cls.EMPTY:<30}{cls.EMPTY:<25}{cls.EMPTY:<30}{cls.EMPTY:<8}{cls.EMPTY:<1}"
f"{cls._dist_vendor(supplier_number)}{cls.EMPTY:<110}{cls.DELIMITER}{os.linesep}"
f"{cls._dist_vendor(ap_line.ap_supplier.supplier_number)}{cls.EMPTY:<110}{cls.DELIMITER}{os.linesep}"
)
return ap_line

Expand Down Expand Up @@ -123,13 +126,13 @@ def get_ap_address(cls, refund_details, routing_slip_number):
return ap_address

@classmethod
def get_eft_ap_comment(cls, comment, refund_id, short_name_id, supplier_number):
def get_eft_ap_comment(cls, comment, refund_id, short_name_id, supplier_line: APSupplier = None):
"""Get AP Comment Override. EFT only."""
line_text = "0001"
combined_comment = f"{cls.EMPTY:<1}{short_name_id}{cls.EMPTY:<1}-{cls.EMPTY:<1}{comment}"[:40]
ap_comment = (
f"{cls._feeder_number()}APIC{cls.DELIMITER}{cls._supplier_number(supplier_number)}"
f"{cls._supplier_location()}{refund_id:<50}{line_text}{combined_comment}"
f"{cls._feeder_number()}APIC{cls.DELIMITER}{cls._supplier_number(supplier_line.supplier_number)}"
f"{cls._supplier_location(supplier_line.supplier_site)}{refund_id:<50}{line_text}{combined_comment}"
f"{cls.DELIMITER}{os.linesep}"
)
return ap_comment
Expand Down Expand Up @@ -175,15 +178,15 @@ def _dist_vendor(cls, supplier_number: str = None):
raise RuntimeError("ap_type not selected.")

@classmethod
def _supplier_location(cls):
def _supplier_location(cls, supplier_site: str = None):
"""Return location."""
match cls.ap_type:
case EjvFileType.NON_GOV_DISBURSEMENT:
return f"{current_app.config.get('BCA_SUPPLIER_LOCATION'):<3}"
case EjvFileType.REFUND:
return f"{current_app.config.get('CGI_AP_SUPPLIER_LOCATION'):<3}"
case EjvFileType.EFT_REFUND:
return f"{current_app.config.get('EFT_AP_SUPPLIER_LOCATION'):<3}"
return f"{supplier_site:<3}"
case _:
raise RuntimeError("ap_type not selected.")

Expand Down
22 changes: 21 additions & 1 deletion jobs/payment-jobs/tasks/common/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Common dataclasses for tasks, dataclasses allow for cleaner code with autocompletion in vscode."""
from dataclasses import dataclass
from dataclasses import dataclass, field
from decimal import Decimal
from sqlite3 import Date
from typing import List, Optional

from dataclass_wizard import JSONWizard
Expand Down Expand Up @@ -70,6 +71,24 @@ class OrderStatus(JSONWizard): # pylint:disable=too-many-instance-attributes
revenue: List[RevenueLine]


@dataclass
class APSupplier:
"""Mapping for supplier items."""

supplier_number: str = None
supplier_site: str = None


@dataclass
class APHeader:
"""Used as a parameter to build AP header."""

total: float
invoice_number: str
invoice_date: Date = None
ap_supplier: APSupplier = field(default_factory=APSupplier)


@dataclass
class APLine:
"""Used as a parameter to build AP inbox files."""
Expand All @@ -79,6 +98,7 @@ class APLine:
line_number: int
is_reversal: Optional[bool] = None
distribution: Optional[str] = None
ap_supplier: APSupplier = field(default_factory=APSupplier)

@classmethod
def from_invoice_and_line_item(
Expand Down
2 changes: 2 additions & 0 deletions jobs/payment-jobs/tests/jobs/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ def factory_create_eft_shortname_historical(

def factory_create_eft_refund(
cas_supplier_number: str = "1234",
cas_supplier_site: str = "123",
comment: str = "Test Comment",
refund_amount: float = 100.0,
refund_email: str = "",
Expand All @@ -458,6 +459,7 @@ def factory_create_eft_refund(
"""Return Factory."""
eft_refund = EFTRefund(
cas_supplier_number=cas_supplier_number,
cas_supplier_site=cas_supplier_site,
comment=comment,
disbursement_status_code=disbursement_status_code,
refund_amount=refund_amount,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""add_eft_cas_supplier_site
Revision ID: 4f3a44eeade8
Revises: c6f04824d529
Create Date: 2024-12-04 16:16:39.574734
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
# Note you may see foreign keys with distribution_codes_history
# For disbursement_distribution_code_id, service_fee_distribution_code_id
# Please ignore those lines and don't include in migration.

revision = '4f3a44eeade8'
down_revision = 'c6f04824d529'
branch_labels = None
depends_on = None


def upgrade():
op.add_column(
"eft_short_names", sa.Column("cas_supplier_site", sa.String(25), nullable=True)
)
op.add_column(
"eft_short_names_history", sa.Column("cas_supplier_site", sa.String(25), nullable=True)
)
op.add_column(
"eft_refunds", sa.Column("cas_supplier_site", sa.String(25), nullable=False)
)


def downgrade():
op.drop_column("eft_refunds", "cas_supplier_site")
op.drop_column("eft_short_names_history", "cas_supplier_site")
op.drop_column("eft_short_names", "cas_supplier_site")
2 changes: 2 additions & 0 deletions pay-api/src/pay_api/models/eft_refund.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class EFTRefund(Audit):
"include_properties": [
"auth_account_id",
"cas_supplier_number",
"cas_supplier_site",
"comment",
"created_by",
"created_name",
Expand All @@ -58,6 +59,7 @@ class EFTRefund(Audit):
}

cas_supplier_number = db.Column(db.String(), nullable=False)
cas_supplier_site = db.Column(db.String(), nullable=False)
comment = db.Column(db.String(), nullable=False)
decline_reason = db.Column(db.String(), nullable=True)
created_by = db.Column("created_by", db.String(100), nullable=True)
Expand Down
4 changes: 4 additions & 0 deletions pay-api/src/pay_api/models/eft_short_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class EFTShortnames(Versioned, BaseModel): # pylint: disable=too-many-instance-
"include_properties": [
"id",
"cas_supplier_number",
"cas_supplier_site",
"created_on",
"email",
"is_generated",
Expand All @@ -59,6 +60,7 @@ class EFTShortnames(Versioned, BaseModel): # pylint: disable=too-many-instance-
short_name = db.Column("short_name", db.String, nullable=False, index=True)
email = db.Column(db.String(100), nullable=True)
cas_supplier_number = db.Column(db.String(), nullable=True)
cas_supplier_site = db.Column(db.String(), nullable=True)
type = db.Column(db.String(), nullable=False)
is_generated = db.Column(db.Boolean(), nullable=False, default=False)

Expand All @@ -85,6 +87,7 @@ class EFTShortnameSchema: # pylint: disable=too-few-public-methods
created_on: datetime
email: str
cas_supplier_number: str
cas_supplier_site: str
short_name: str
short_name_type: str
statement_id: int
Expand All @@ -108,6 +111,7 @@ def from_row(cls, row: EFTShortnames):
short_name_type=row.type,
email=getattr(row, "email"),
cas_supplier_number=getattr(row, "cas_supplier_number"),
cas_supplier_site=getattr(row, "cas_supplier_site"),
statement_id=getattr(row, "latest_statement_id", None),
status_code=getattr(row, "status_code", None),
cfs_account_status=getattr(row, "cfs_account_status", None),
Expand Down
Loading

0 comments on commit 10eeaa9

Please sign in to comment.