Update .gitignore and enhance CSRF controller and WHMCS services

- Added exceptions to .gitignore for the portal public directory to ensure proper asset management.
- Marked CSRF token retrieval and refresh endpoints as public for improved access control.
- Refactored WHMCS invoice service to enhance error logging and processing of invoice records.
- Updated WHMCS raw types to introduce a common schema for invoices, improving data consistency and validation.
- Enhanced Salesforce order item transformation to streamline billing cycle handling.
This commit is contained in:
barsa 2025-10-21 16:30:52 +09:00
parent cff6c21bae
commit 7cefee4c75
10 changed files with 111 additions and 89 deletions

2
.gitignore vendored
View File

@ -117,6 +117,8 @@ dist/
# Gatsby files
.cache/
public/
!apps/portal/public/
!apps/portal/public/**
# Storybook build outputs
.out/

View File

@ -2,6 +2,7 @@ import { Controller, Get, Post, Req, Res, Inject } from "@nestjs/common";
import type { Request, Response } from "express";
import { Logger } from "nestjs-pino";
import { CsrfService } from "../services/csrf.service";
import { Public } from "@bff/modules/auth/decorators/public.decorator";
type AuthenticatedRequest = Request & {
user?: { id: string; sessionId?: string };
@ -15,6 +16,7 @@ export class CsrfController {
@Inject(Logger) private readonly logger: Logger
) {}
@Public()
@Get("token")
getCsrfToken(@Req() req: AuthenticatedRequest, @Res() res: Response) {
const sessionId = req.user?.sessionId || this.extractSessionId(req) || undefined;
@ -46,6 +48,7 @@ export class CsrfController {
});
}
@Public()
@Post("refresh")
refreshCsrfToken(@Req() req: AuthenticatedRequest, @Res() res: Response) {
const sessionId = req.user?.sessionId || this.extractSessionId(req) || undefined;

View File

@ -60,7 +60,6 @@ export function buildOrderItemSelectFields(
"UnitPrice",
"TotalPrice",
"PricebookEntry.Id",
"Billing_Cycle__c",
"WHMCS_Service_ID__c",
];

View File

@ -211,8 +211,10 @@ export class WhmcsInvoiceService {
} satisfies InvoiceList;
}
const invoiceRecords = response.invoices.invoice;
const invoices: Invoice[] = [];
for (const whmcsInvoice of response.invoices.invoice) {
for (const whmcsInvoice of invoiceRecords) {
try {
// Transform using domain mapper
const defaultCurrency = this.currencyService.getDefaultCurrency();
@ -223,8 +225,9 @@ export class WhmcsInvoiceService {
const parsed = invoiceSchema.parse(transformed as unknown);
invoices.push(parsed);
} catch (error) {
this.logger.error(`Failed to transform invoice ${whmcsInvoice.id}`, {
this.logger.error(`Failed to transform WHMCS invoice ${whmcsInvoice?.id ?? "unknown"}`, {
error: getErrorMessage(error),
rawInvoice: whmcsInvoice,
});
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1045" height="1056">
<path d="M0 0 C47.44591133 7.10096175 103.91534409 29.12476061 133.890625 68.69921875 C147.88368872 88.21283363 152.53866095 110.67680581 148.74609375 134.34765625 C143.51493154 159.9557016 130.3405656 182.90083774 114 203 C113.26136719 203.93070313 112.52273438 204.86140625 111.76171875 205.8203125 C106.96884388 211.79650816 101.908653 217.4719415 96.69921875 223.08203125 C94.2052426 225.77812414 91.75374381 228.50622684 89.3125 231.25 C83.64783287 237.5496743 77.74676921 243.44174527 71.3203125 248.9609375 C68.95956661 251.03553238 66.66052195 253.16482269 64.36401367 255.30981445 C58.99163971 260.32543837 53.5290145 265.13229501 47.79296875 269.734375 C45.29743102 271.75872728 42.85330709 273.83238521 40.41967773 275.93041992 C33.26569239 282.08243436 25.80739379 287.74651825 18.22021484 293.35058594 C15.88241197 295.08735702 13.55906912 296.84212719 11.23828125 298.6015625 C-16.81515753 319.85030238 -46.1792947 339.32824397 -76 358 C-76.81033691 358.50982422 -77.62067383 359.01964844 -78.45556641 359.54492188 C-84.60749119 363.41219791 -90.79345218 367.22107058 -97 371 C-97.62803528 371.38295227 -98.25607056 371.76590454 -98.90313721 372.16046143 C-103.1830707 374.7685519 -107.47098298 377.36289903 -111.76739502 379.9437561 C-113.20434659 380.80869546 -114.63939829 381.67679967 -116.07244873 382.54818726 C-118.09362907 383.77584071 -120.12191367 384.99084771 -122.15234375 386.203125 C-123.05582298 386.75686546 -123.05582298 386.75686546 -123.97755432 387.3217926 C-127.64062688 389.48718819 -130.72376597 390.83951443 -135 391 C-137.48754883 390.05053711 -137.48754883 390.05053711 -139.95703125 388.52734375 C-140.89160156 387.96466797 -141.82617188 387.40199219 -142.7890625 386.82226562 C-143.78679687 386.20029297 -144.78453125 385.57832031 -145.8125 384.9375 C-147.97393093 383.63191106 -150.13673447 382.32859226 -152.30078125 381.02734375 C-153.96488037 380.01969971 -153.96488037 380.01969971 -155.66259766 378.99169922 C-160.87805312 375.87921307 -166.18632725 372.940564 -171.5 370 C-180.77578753 364.8402845 -189.96633778 359.55079596 -199.12109375 354.1796875 C-205.87821523 350.22105932 -212.67341662 346.3374768 -219.5 342.5 C-227.33635271 338.09489425 -235.12136287 333.61157003 -242.875 329.0625 C-252.06657519 323.67186228 -261.33334633 318.43193096 -270.64404297 313.25024414 C-278.81963993 308.68908814 -286.9076146 303.99002445 -294.98046875 299.25 C-302.10528525 295.07755844 -309.28553837 291.01518978 -316.5 287 C-325.64402978 281.90904176 -334.71202485 276.704054 -343.73876953 271.40820312 C-352.91214718 266.03210715 -362.14210532 260.75800919 -371.38598633 255.50439453 C-377.97605283 251.75274977 -384.51935345 247.9378865 -391 244 C-387.96305297 242.30394363 -385.28736907 241.55486926 -381.86108398 241.0012207 C-380.81917404 240.82894958 -379.7772641 240.65667847 -378.70378113 240.47918701 C-377.56274429 240.29656311 -376.42170746 240.11393921 -375.24609375 239.92578125 C-372.73199691 239.50979654 -370.21800469 239.09317919 -367.70410156 238.67602539 C-366.3480366 238.45280512 -364.99195721 238.22967245 -363.63586426 238.00662231 C-308.34557213 228.88831221 -253.32964047 217.89048908 -198.86645508 204.69348145 C-196.02459706 204.00595077 -193.18143143 203.32408859 -190.33789062 202.64355469 C-129.44938766 188.03987142 -68.060326 171.19013369 -11 145 C-9.54859619 144.33701904 -9.54859619 144.33701904 -8.06787109 143.66064453 C15.09901789 133.01619399 36.7225208 120.97740118 55 103 C56.01707031 102.01966797 56.01707031 102.01966797 57.0546875 101.01953125 C65.60308861 92.11019765 70.4224772 80.54012553 70.2734375 68.2890625 C69.44959778 58.37944763 65.12148393 50.62345627 59 43 C58.42636719 42.26265625 57.85273437 41.5253125 57.26171875 40.765625 C42.55446193 23.00354181 19.94148407 11.76887789 0 1 C0 0.67 0 0.34 0 0 Z " fill="#161C60" transform="translate(653,655)"/>
<path d="M0 0 C2.580739 1.31680947 5.13576179 2.6495294 7.66308594 4.06665039 C8.65115234 4.6196582 9.63921875 5.17266602 10.65722656 5.74243164 C12.24374023 6.63768555 12.24374023 6.63768555 13.86230469 7.55102539 C14.97025391 8.17364258 16.07820313 8.79625977 17.21972656 9.43774414 C25.70557395 14.22216405 34.12481286 19.11608475 42.52563477 24.0480957 C49.65180864 28.22183976 56.8336943 32.28503974 64.04980469 36.30102539 C73.32426136 41.46319576 82.5160836 46.7501949 91.67089844 52.12133789 C98.42801991 56.07996607 105.22322131 59.9635486 112.04980469 63.80102539 C119.8861574 68.20613114 127.67116755 72.68945536 135.42480469 77.23852539 C144.61637988 82.62916311 153.88315102 87.86909443 163.19384766 93.05078125 C171.36944462 97.61193725 179.45741929 102.31100094 187.53027344 107.05102539 C194.65509038 111.22346721 201.83534663 115.28582759 209.04980469 119.30102539 C220.4139563 125.62821408 231.6813211 132.11334099 242.88134766 138.72680664 C244.72520205 139.81456265 246.57348858 140.89482811 248.42529297 141.96899414 C249.3339209 142.50137695 250.24254883 143.03375977 251.17871094 143.58227539 C251.9954126 144.05729492 252.81211426 144.53231445 253.65356445 145.02172852 C255.54980469 146.30102539 255.54980469 146.30102539 256.54980469 148.30102539 C255.86347961 148.41662811 255.17715454 148.53223083 254.47003174 148.65133667 C155.15913688 165.39567478 56.02223126 184.60931104 -196.45019531 296.30102539 C-202.32741965 305.44483201 -205.70692142 314.30864896 -204.45019531 325.30102539 C-199.60037826 346.99451842 -182.3598666 360.95827407 -164.59423828 372.50756836 C-154.86845626 378.67835584 -144.67197551 384.00872059 -134.45019531 389.30102539 C-134.78019531 389.96102539 -135.11019531 390.62102539 -135.45019531 391.30102539 C-184.09012963 380.66958913 -242.33290496 361.4040507 -271.20019531 317.42602539 C-283.76751824 297.57356989 -287.07746124 275.04039205 -281.98925781 252.23510742 C-271.21249181 207.95710634 -236.61899267 168.18966273 -202.59863281 139.16821289 C-200.41817047 137.27319289 -198.29641433 135.32163941 -196.17944336 133.35620117 C-190.13093042 127.74540326 -183.88103697 122.47238963 -177.45019531 117.30102539 C-176.26808246 116.32843069 -175.08716125 115.35438644 -173.90722656 114.37915039 C-157.6365968 100.9692907 -140.6220452 88.52626464 -123.45019531 76.30102539 C-122.86757935 75.8845575 -122.28496338 75.4680896 -121.68469238 75.03900146 C-110.9679855 67.38444944 -100.09995052 60.00371407 -89.07519531 52.80102539 C-87.52106685 51.78330073 -85.96694913 50.76555966 -84.4128418 49.74780273 C-66.38559997 37.95459872 -48.13702051 26.5681139 -29.67791748 15.46464539 C-25.74475284 13.09466592 -21.83937985 10.68335418 -17.94238281 8.25415039 C-15.96601042 7.04029915 -13.98945829 5.82674047 -12.01269531 4.61352539 C-10.66437622 3.75706421 -10.66437622 3.75706421 -9.28881836 2.88330078 C-8.45648682 2.37790771 -7.62415527 1.87251465 -6.76660156 1.35180664 C-6.04931885 0.90490479 -5.33203613 0.45800293 -4.59301758 -0.00244141 C-2.45019531 -0.69897461 -2.45019531 -0.69897461 0 0 Z " fill="#28A6E0" transform="translate(531.4501953125,0.698974609375)"/>
<path d="M0 0 C2.17930043 0.00565272 4.35859303 0.00846567 6.53789902 0.0110817 C28.02620185 0.04854229 49.36700311 0.49355767 70.72164536 3.06482315 C72.92828848 3.32982727 75.1359904 3.58437665 77.34395981 3.83807755 C106.14869015 7.18880093 134.50625619 12.62671061 162.76778793 19.06805801 C164.64325302 19.49030655 164.64325302 19.49030655 166.55660629 19.92108536 C167.70781967 20.19130508 168.85903305 20.46152481 170.04513168 20.73993301 C171.54741318 21.08943008 171.54741318 21.08943008 173.08004379 21.4459877 C178.03863793 23.01830002 181.06236736 25.08532597 183.86935043 29.45477676 C184.43484604 30.32014053 185.00034164 31.1855043 185.58297348 32.07709122 C186.20083725 33.04348526 186.81870102 34.0098793 187.45528793 35.00555801 C188.50857006 36.61834561 189.56195966 38.23106479 190.61774826 39.84221268 C191.39690404 41.03139695 192.17490822 42.22133638 192.95188522 43.41194534 C197.8239683 50.86766787 202.82314842 58.23747781 207.81469345 65.61349869 C210.11570539 69.01423988 212.41381401 72.41693875 214.71198654 75.81959915 C216.50768235 78.47827026 218.30374595 81.13669265 220.09981918 83.7951088 C225.94139505 92.44253418 231.77783906 101.09342186 237.61339951 109.74490738 C239.47080571 112.49840946 241.32863655 115.25162467 243.18648911 118.00482559 C252.54793101 131.8813305 252.54793101 131.8813305 256.75606918 138.20868301 C262.89962974 147.44383656 269.12416472 156.62489733 275.33028793 165.81805801 C289.56338834 186.90161929 289.56338834 186.90161929 295.68770981 196.11102676 C300.40348305 203.16964086 305.16531387 210.19741376 309.91592026 217.2326088 C327.73383477 243.62345963 327.73383477 243.62345963 336.20528793 256.31805801 C337.09280746 257.64595352 337.09280746 257.64595352 337.99825668 259.0006752 C342.02810919 265.05253216 345.94640791 271.17162435 349.83028793 277.31805801 C346.79826409 276.70755252 344.68555049 275.75364767 342.13497543 274.01727676 C341.42921371 273.541371 340.723452 273.06546524 339.99630356 272.57513809 C339.2402684 272.05717667 338.48423325 271.53921524 337.70528793 271.00555801 C336.06733536 269.89868616 334.42931271 268.79191801 332.79122543 267.68524551 C331.54357407 266.83784805 331.54357407 266.83784805 330.27071762 265.97333145 C326.6357986 263.50787017 322.98471304 261.06698123 319.33028793 258.63055801 C318.60446518 258.14643448 317.87864243 257.66231094 317.13082504 257.163517 C290.99242535 239.7610723 264.6113307 222.71563762 237.83028793 206.31805801 C236.76971176 205.66724258 235.70913559 205.01642715 234.61642075 204.34589005 C217.84160128 194.0619871 200.92604521 184.06217695 183.83028793 174.31805801 C181.91230262 173.21912858 179.99433343 172.12017102 178.07638168 171.02118301 C95.5043368 123.85661596 7.34877151 82.07312577 -191.16971207 70.31805801 C-192.17481827 70.4566423 -192.17481827 70.4566423 -193.20022964 70.59802628 C-223.92370564 74.84589478 -255.07167909 80.46029887 -284.9253273 88.92865372 C-287.35097262 89.34950701 -288.85595495 89.09753056 -291.16971207 88.31805801 C-272.93315107 72.43305357 -250.87719937 60.82371483 -229.22244644 50.32001114 C-227.12918417 49.29827608 -225.04805916 48.25419746 -222.96658707 47.20868301 C-175.85142589 23.86516732 -123.24113498 10.93711463 -71.29471207 4.06805801 C-70.15767838 3.91691544 -69.02064468 3.76577286 -67.84915543 3.6100502 C-45.2763079 0.80722729 -22.72529317 -0.05994174 0 0 Z " fill="#28A6E0" transform="translate(689.1697120666504,221.68194198608398)"/>
<path d="M0 0 C11.00238163 6.886688 21.79625369 14.09519595 32.625 21.25 C59.83655085 39.22750478 87.19934318 56.94358091 115 74 C116.05429199 74.64839844 117.10858398 75.29679688 118.19482422 75.96484375 C135.60428341 86.65969515 153.19499829 96.97806828 171 107 C172.11729492 107.63147949 173.23458984 108.26295898 174.38574219 108.91357422 C191.71485533 118.69743924 209.26744237 127.97572521 227 137 C227.77811035 137.39735352 228.5562207 137.79470703 229.35791016 138.20410156 C233.12022091 140.12235789 236.89782796 142.00614989 240.69042969 143.86376953 C242.41769885 144.71352753 244.14179934 145.56973179 245.86425781 146.42919922 C277.64248795 162.26991613 310.28003124 175.86436045 344 187 C345.75425293 187.57935303 345.75425293 187.57935303 347.54394531 188.17041016 C391.47015987 202.49638943 437.02853593 211.21398753 483.3125 211.25 C484.10724731 211.25067474 484.90199463 211.25134949 485.7208252 211.25204468 C533.60616507 211.18847796 580.92483676 202.01856054 627.30053711 190.72680664 C628.25581299 190.49727295 629.21108887 190.26773926 630.1953125 190.03125 C631.01016113 189.83080078 631.82500977 189.63035156 632.66455078 189.42382812 C635.15574462 188.97173608 637.47353911 188.92597273 640 189 C636.48065547 192.68942437 632.79832701 195.80997042 628.625 198.75 C627.71089355 199.39678711 627.71089355 199.39678711 626.77832031 200.05664062 C620.06602628 204.74186988 613.09273768 208.92202557 606 213 C605.34644531 213.38091797 604.69289063 213.76183594 604.01953125 214.15429688 C542.36270924 249.9915793 472.55854088 268.74928289 402 276 C400.85257324 276.11859375 399.70514648 276.2371875 398.52294922 276.359375 C362.45956181 279.87010893 325.04578376 279.52032305 289 276 C287.70771484 275.87641113 286.41542969 275.75282227 285.08398438 275.62548828 C251.93302382 272.38307774 218.67259651 267.01304644 186.36938477 258.83032227 C184.03299035 258.25456128 181.67929333 257.74643202 179.31616211 257.29272461 C172.91105093 255.88406814 168.71921845 254.57740994 164.71484375 249.21484375 C163.41633861 247.14660967 162.15972489 245.05170769 160.9375 242.9375 C160.22187475 241.77487367 159.50112915 240.61538692 158.77587891 239.45874023 C157.56952083 237.53440483 156.36648201 235.60865634 155.17687988 233.67390442 C149.67036251 224.74213275 143.71728057 216.10607583 137.82131958 207.4289856 C134.70223546 202.83528485 131.59732045 198.23204375 128.4921875 193.62890625 C127.61799919 192.3339045 127.61799919 192.3339045 126.72615051 191.01274109 C123.8179335 186.70292762 120.91812847 182.38796419 118.0390625 178.05859375 C111.90829409 168.83965622 105.69460343 159.67609637 99.5 150.5 C85.2705857 129.42189896 85.2705857 129.42189896 79.17773438 120.25976562 C73.64995314 111.98544555 68.06771161 103.74747845 62.5 95.5 C48.2705857 74.42189896 48.2705857 74.42189896 42.17773438 65.25976562 C36.64995314 56.98544555 31.06771161 48.74747845 25.5 40.5 C22.94752865 36.7190117 20.39540062 32.93779223 17.84375 29.15625 C17.23772949 28.2583374 16.63170898 27.3604248 16.00732422 26.43530273 C12.15704758 20.72683987 8.3281569 15.00519844 4.53320312 9.25976562 C3.03079704 6.97947094 3.03079704 6.97947094 1.29492188 4.88085938 C0 3 0 3 0 0 Z " fill="#161C60" transform="translate(12,547)"/>
<path d="M0 0 C0.33 0.66 0.66 1.32 1 2 C0.14621021 4.29681479 -0.76856867 6.50860791 -1.75 8.75 C-10.39558164 29.70891004 -10.74451996 52.09621038 -2.375 73.19921875 C18.3525406 122.26314396 75.38117919 150.14425213 121.94917297 169.18585205 C178.42794703 191.99171465 237.39322601 206.20005938 297 218 C297 218.33 297 218.66 297 219 C271.12702272 219.12686912 245.27158451 218.77938204 219.40310669 218.32365608 C213.6722625 218.2233555 207.94135996 218.12649245 202.21046448 218.0291748 C192.32303983 217.86082088 182.43565314 217.69037394 172.54829025 217.51843262 C158.25349236 217.26984911 143.95863976 217.02453527 129.66377254 216.77997446 C106.46135582 216.38293386 83.25898425 215.98331844 60.05664062 215.58203125 C37.5413647 215.19263322 15.02606792 214.80447646 -7.48925781 214.41796875 C-8.18549815 214.4060163 -8.88173848 214.39406386 -9.599077 214.38174921 C-16.59216411 214.26169934 -23.58525164 214.14167437 -30.57833948 214.02166761 C-89.05229128 213.01820743 -147.52617062 212.01056838 -206 211 C-204.52002674 207.90411588 -203.02886795 205.78793437 -200.5793457 203.36816406 C-199.53234245 202.32622894 -199.53234245 202.32622894 -198.46418762 201.26324463 C-197.70901352 200.52153015 -196.95383942 199.77981567 -196.17578125 199.015625 C-195.00634224 197.85398834 -195.00634224 197.85398834 -193.8132782 196.66888428 C-191.31771638 194.19113021 -188.81559722 191.72013957 -186.3125 189.25 C-183.82808268 186.79333479 -181.34518253 184.33518545 -178.86528015 181.8739624 C-177.32318699 180.34397601 -175.77842961 178.81666847 -174.23054504 177.2925415 C-170.9233511 174.0156083 -167.70858392 170.72024951 -164.68041992 167.18261719 C-160.43884821 162.25939996 -155.82462139 157.71230827 -151.21405029 153.1388855 C-149.58766731 151.52546486 -147.96460304 149.90876729 -146.34228516 148.29125977 C-142.31536577 144.27758899 -138.28297337 140.26943165 -134.25073242 136.2611084 C-130.8317138 132.86194276 -127.41483601 129.46065133 -124.00067139 126.05661011 C-122.41478994 124.47712934 -120.82588904 122.90073203 -119.23681641 121.32446289 C-114.59815949 116.70907096 -110.10369723 112.04310956 -105.84741211 107.07226562 C-102.20707838 102.98885704 -98.28215096 99.17502553 -94.39924622 95.32408142 C-92.80646509 93.74426867 -91.21700843 92.16117414 -89.6282959 90.57727051 C-85.68485384 86.64707341 -81.73593714 82.72239228 -77.78717041 78.79754639 C-74.43860973 75.46884286 -71.09219307 72.13801069 -67.74848938 68.8044281 C-66.19584762 67.25818445 -64.64018597 65.7150262 -63.08435059 64.17199707 C-58.50004042 59.61119305 -54.06460153 54.99557259 -49.85726929 50.08435059 C-45.71598669 45.43672901 -41.22832786 41.10775064 -36.81640625 36.71875 C-35.75001915 35.65423228 -34.68385581 34.58949038 -33.61790466 33.52453613 C-30.83694593 30.74736167 -28.05299556 27.97320575 -25.26837158 25.19970703 C-22.4173052 22.35894362 -19.56913331 19.51528128 -16.72070312 16.671875 C-11.14993482 11.1117717 -5.57599681 5.55485982 0 0 Z " fill="#28A6E0" transform="translate(214,243)"/>
<path d="M0 0 C46.51639515 -0.31114165 93.00877674 0.51273555 139.51632003 1.32304173 C150.78140801 1.51916607 162.0465819 1.71013813 173.31175986 1.90101171 C193.43430586 2.24212737 213.55677369 2.58764741 233.67919922 2.93579102 C253.09548596 3.27171314 272.5118229 3.60451206 291.92822266 3.93383789 C293.72730806 3.96435324 293.72730806 3.96435324 295.56273863 3.99548506 C296.76030209 4.01579714 297.95786555 4.03610922 299.19171882 4.05703682 C321.48284558 4.43513566 343.77392594 4.81590826 366.06498365 5.19805495 C372.77326474 5.31301568 379.48155347 5.4275179 386.18984845 5.54166489 C396.82286331 5.72259491 407.45585388 5.90483906 418.08880141 6.08968716 C422.92984062 6.17382179 427.77088744 6.25738889 432.61196709 6.33916664 C456.08024079 6.73615213 479.53962505 7.26929935 503 8 C501.37442679 11.43859035 499.56051315 13.67745192 496.8449707 16.36621094 C495.55771843 17.64839508 495.55771843 17.64839508 494.24446106 18.95648193 C493.31429672 19.87318665 492.38413239 20.78989136 491.42578125 21.734375 C490.45840726 22.69546983 489.49155244 23.65708747 488.52519226 24.61920166 C485.9789987 27.15210378 483.42730879 29.67938891 480.8739624 32.20507812 C476.80453657 36.23139665 472.7416605 40.26429214 468.68227196 44.30072784 C467.27404991 45.69886256 465.86220622 47.09334653 464.45027161 48.48773193 C460.69860401 52.21136313 456.99712711 55.92475393 453.55737305 59.94042969 C449.41989642 64.76197265 444.90722778 69.20504273 440.39924622 73.67591858 C438.80646509 75.25573133 437.21700843 76.83882586 435.6282959 78.42272949 C431.68485384 82.35292659 427.73593714 86.27760772 423.78717041 90.20245361 C420.43860973 93.53115714 417.09219307 96.86198931 413.74848938 100.1955719 C412.19584762 101.74181555 410.64018597 103.2849738 409.08435059 104.82800293 C405.11013086 108.78186729 401.16184863 112.72568374 397.51367188 116.98632812 C393.33742176 121.86104731 388.768129 126.34372895 384.21405029 130.8611145 C382.58766731 132.47453514 380.96460304 134.09123271 379.34228516 135.70874023 C375.31536577 139.72241101 371.28297337 143.73056835 367.25073242 147.7388916 C363.8317138 151.13805724 360.41483601 154.53934867 357.00067139 157.94338989 C355.41478994 159.52287066 353.82588904 161.09926797 352.23681641 162.67553711 C347.55991987 167.32895757 343.01991324 172.03149878 338.72872925 177.04418945 C335.25860408 180.97014108 331.50051076 184.62061821 327.78515625 188.3125 C326.92941513 189.16682617 326.07367401 190.02115234 325.19200134 190.90136719 C322.48452619 193.60328862 319.77357746 196.30169359 317.0625 199 C315.21526325 200.84221577 313.36825573 202.68466143 311.52148438 204.52734375 C307.01696997 209.02089061 302.50960595 213.5115632 298 218 C296.6957369 214.08721069 297.65516374 212.87378179 299.25 209.125 C307.87797703 187.45919102 307.77698639 165.62817069 299 144 C274.15911659 89.91997202 208.97079612 61.78267469 156.5625 42.3125 C105.85846791 23.63985095 53.24348498 10.13007323 0 1 C0 0.67 0 0.34 0 0 Z " fill="#161C60" transform="translate(539,585)"/>
</svg>

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -9,6 +9,8 @@ import { invoiceSchema } from "../../schema";
import {
type WhmcsInvoiceRaw,
whmcsInvoiceRawSchema,
type WhmcsInvoiceListItem,
whmcsInvoiceListItemSchema,
type WhmcsInvoiceItemsRaw,
whmcsInvoiceItemsRawSchema,
} from "./raw.types";
@ -94,8 +96,15 @@ export function transformWhmcsInvoice(
rawInvoice: unknown,
options: TransformInvoiceOptions = {}
): Invoice {
// Validate raw data
const whmcsInvoice = whmcsInvoiceRawSchema.parse(rawInvoice);
const invoicePayload =
rawInvoice && typeof (rawInvoice as { invoiceid?: unknown }).invoiceid !== "undefined"
? whmcsInvoiceRawSchema.parse(rawInvoice)
: normalizeListInvoice(rawInvoice);
const whmcsInvoice = {
...invoicePayload,
invoiceid: invoicePayload.invoiceid ?? invoicePayload.id,
};
const currency = whmcsInvoice.currencycode || options.defaultCurrencyCode || "JPY";
const currencySymbol =
@ -105,7 +114,7 @@ export function transformWhmcsInvoice(
// Transform to domain model
const invoice: Invoice = {
id: whmcsInvoice.invoiceid ?? whmcsInvoice.id ?? 0,
id: whmcsInvoice.invoiceid ?? 0,
number: whmcsInvoice.invoicenum || `INV-${whmcsInvoice.invoiceid}`,
status: mapStatus(whmcsInvoice.status),
currency,
@ -133,3 +142,12 @@ export function transformWhmcsInvoices(
): Invoice[] {
return rawInvoices.map(raw => transformWhmcsInvoice(raw, options));
}
function normalizeListInvoice(rawInvoice: unknown): WhmcsInvoiceRaw & { id?: number } {
const listItem: WhmcsInvoiceListItem = whmcsInvoiceListItemSchema.parse(rawInvoice);
const invoiceid = listItem.invoiceid ?? listItem.id;
return {
...listItem,
invoiceid,
};
}

View File

@ -110,39 +110,59 @@ export const whmcsInvoiceItemsRawSchema = z.object({
export type WhmcsInvoiceItemsRaw = z.infer<typeof whmcsInvoiceItemsRawSchema>;
// Raw WHMCS Invoice
export const whmcsInvoiceRawSchema = z.object({
const whmcsInvoiceCommonSchema = z
.object({
invoicenum: z.string().optional(),
userid: z.number(),
date: z.string(),
duedate: z.string(),
subtotal: z.string(),
credit: z.string(),
tax: z.string(),
tax2: z.string(),
total: z.string(),
balance: z.string().optional(),
status: z.string(),
paymentmethod: z.string(),
notes: z.string().optional(),
ccgateway: z.boolean().optional(),
items: whmcsInvoiceItemsRawSchema.optional(),
transactions: z.unknown().optional(),
clientid: z.number().optional(),
datecreated: z.string().optional(),
paymentmethodname: z.string().optional(),
currencyprefix: z.string().optional(),
currencysuffix: z.string().optional(),
lastcaptureattempt: z.string().optional(),
last_capture_attempt: z.string().optional(),
datepaid: z.string().optional(),
date_refunded: z.string().optional(),
date_cancelled: z.string().optional(),
created_at: z.string().optional(),
updated_at: z.string().optional(),
taxrate: z.string().optional(),
taxrate2: z.string().optional(),
firstname: z.string().optional(),
lastname: z.string().optional(),
companyname: z.string().optional(),
currencycode: z.string().optional(),
})
.passthrough();
export const whmcsInvoiceListItemSchema = whmcsInvoiceCommonSchema.extend({
id: z.number(),
invoiceid: z.number().optional(),
});
// Raw WHMCS Invoice (detailed GetInvoice response)
export const whmcsInvoiceRawSchema = whmcsInvoiceCommonSchema.extend({
invoiceid: z.number(),
invoicenum: z.string(),
userid: z.number(),
date: z.string(),
duedate: z.string(),
subtotal: z.string(),
credit: z.string(),
tax: z.string(),
tax2: z.string(),
total: z.string(),
balance: z.string().optional(),
status: z.string(),
paymentmethod: z.string(),
notes: z.string().optional(),
ccgateway: z.boolean().optional(),
items: whmcsInvoiceItemsRawSchema.optional(),
transactions: z.unknown().optional(),
id: z.number().optional(),
clientid: z.number().optional(),
datecreated: z.string().optional(),
paymentmethodname: z.string().optional(),
currencycode: z.string().optional(),
currencyprefix: z.string().optional(),
currencysuffix: z.string().optional(),
lastcaptureattempt: z.string().optional(),
taxrate: z.string().optional(),
taxrate2: z.string().optional(),
datepaid: z.string().optional(),
balance: z.string().optional(),
});
export type WhmcsInvoiceRaw = z.infer<typeof whmcsInvoiceRawSchema>;
export type WhmcsInvoiceListItem = z.infer<typeof whmcsInvoiceListItemSchema>;
// ============================================================================
// WHMCS Invoice List Response (GetInvoices API)
@ -153,7 +173,7 @@ export type WhmcsInvoiceRaw = z.infer<typeof whmcsInvoiceRawSchema>;
*/
export const whmcsInvoiceListResponseSchema = z.object({
invoices: z.object({
invoice: z.array(whmcsInvoiceRawSchema),
invoice: z.array(whmcsInvoiceListItemSchema),
}),
totalresults: z.number(),
numreturned: z.number(),
@ -264,4 +284,3 @@ export const whmcsCurrenciesResponseSchema = z.object({
}).catchall(z.string().or(z.number()));
export type WhmcsCurrenciesResponse = z.infer<typeof whmcsCurrenciesResponseSchema>;

View File

@ -25,6 +25,8 @@ export function transformSalesforceOrderItem(
// PricebookEntry is unknown to avoid circular dependencies between domains
const pricebookEntry = record.PricebookEntry as Record<string, any> | null | undefined;
const product = pricebookEntry?.Product2 as Record<string, any> | undefined;
const productBillingCycle = product?.Billing_Cycle__c ?? undefined;
const billingCycle = record.Billing_Cycle__c ?? productBillingCycle ?? undefined;
const details = orderItemDetailsSchema.parse({
id: record.Id,
@ -32,7 +34,7 @@ export function transformSalesforceOrderItem(
quantity: normalizeQuantity(record.Quantity),
unitPrice: coerceNumber(record.UnitPrice),
totalPrice: coerceNumber(record.TotalPrice),
billingCycle: record.Billing_Cycle__c ?? undefined,
billingCycle,
product: product
? {
id: product.Id ?? undefined,

View File

@ -8,39 +8,6 @@
import { z } from "zod";
const normalizeRequiredNumber = z.preprocess(
value => {
if (typeof value === "number") return value;
if (typeof value === "string" && value.trim().length > 0) {
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : value;
}
return value;
},
z.number()
);
const normalizeOptionalNumber = z.preprocess(
value => {
if (value === undefined || value === null || value === "") return undefined;
if (typeof value === "number") return value;
if (typeof value === "string") {
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : undefined;
}
return undefined;
},
z.number().optional()
);
const normalizeOptionalString = z.preprocess(
value => {
if (value === undefined || value === null || value === "") return undefined;
return String(value);
},
z.string().optional()
);
// ============================================================================
// Request Parameter Types
// ============================================================================
@ -77,12 +44,12 @@ export const whmcsCustomFieldsContainerSchema = z.object({
// Raw WHMCS Product/Service (Subscription)
export const whmcsProductRawSchema = z.object({
id: normalizeRequiredNumber,
clientid: normalizeRequiredNumber,
serviceid: normalizeOptionalNumber,
pid: normalizeOptionalNumber,
orderid: normalizeOptionalNumber,
ordernumber: normalizeOptionalString,
id: z.number(),
clientid: z.number(),
serviceid: z.number().optional(),
pid: z.number().optional(),
orderid: z.number().optional(),
ordernumber: z.string().optional(),
regdate: z.string(),
name: z.string(),
translated_name: z.string().optional(),
@ -90,12 +57,12 @@ export const whmcsProductRawSchema = z.object({
translated_groupname: z.string().optional(),
domain: z.string().optional(),
dedicatedip: z.string().optional(),
serverid: normalizeOptionalNumber,
serverid: z.number().optional(),
servername: z.string().optional(),
serverip: z.string().optional(),
serverhostname: z.string().optional(),
suspensionreason: z.string().optional(),
promoid: normalizeOptionalNumber,
promoid: z.number().optional(),
subscriptionid: z.string().optional(),
// Pricing
@ -117,10 +84,10 @@ export const whmcsProductRawSchema = z.object({
// Notes
notes: z.string().optional(),
diskusage: normalizeOptionalNumber,
disklimit: normalizeOptionalNumber,
bwusage: normalizeOptionalNumber,
bwlimit: normalizeOptionalNumber,
diskusage: z.number().optional(),
disklimit: z.number().optional(),
bwusage: z.number().optional(),
bwlimit: z.number().optional(),
lastupdate: z.string().optional(),
// Custom fields
@ -148,13 +115,13 @@ export type WhmcsCustomField = z.infer<typeof whmcsCustomFieldSchema>;
export const whmcsProductListResponseSchema = z.object({
result: z.enum(["success", "error"]).optional(),
message: z.string().optional(),
clientid: z.union([z.number(), z.string()]).optional(),
serviceid: z.union([z.number(), z.string(), z.null()]).optional(),
pid: z.union([z.number(), z.string(), z.null()]).optional(),
domain: z.string().nullable().optional(),
totalresults: z.union([z.number(), z.string()]).optional(),
startnumber: normalizeOptionalNumber,
numreturned: normalizeOptionalNumber,
clientid: z.number().optional(),
serviceid: z.number().optional(),
pid: z.number().optional(),
domain: z.string().optional(),
totalresults: z.number().optional(),
startnumber: z.number().optional(),
numreturned: z.number().optional(),
products: z.object({
product: z.union([whmcsProductRawSchema, z.array(whmcsProductRawSchema)]).optional(),
}).optional(),