@sbc-connect/nuxt-pay 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.example CHANGED
@@ -1,16 +1,29 @@
1
1
  # Web Urls
2
2
  NUXT_PUBLIC_BASE_URL="http://localhost:3000/"
3
3
  NUXT_PUBLIC_REGISTRY_HOME_URL="https://dev.bcregistry.gov.bc.ca/"
4
+ NUXT_PUBLIC_AUTH_WEB_URL="https://dev.account.bcregistry.gov.bc.ca/"
5
+
6
+ # API Key
7
+ NUXT_PUBLIC_X_API_KEY=""
4
8
 
5
9
  # API Urls
6
10
  # Status API
7
11
  NUXT_PUBLIC_STATUS_API_URL="https://status-api-dev.apps.gold.devops.gov.bc.ca"
8
12
  NUXT_PUBLIC_STATUS_API_VERSION="/api/v1"
9
13
 
14
+ # Auth API
15
+ NUXT_PUBLIC_AUTH_API_URL="https://test.api.connect.gov.bc.ca/auth-dev"
16
+ NUXT_PUBLIC_AUTH_API_VERSION="/api/v1"
17
+
18
+ # Pay API
19
+ NUXT_PUBLIC_PAY_API_URL="https://test.api.connect.gov.bc.ca/pay-dev"
20
+ NUXT_PUBLIC_PAY_API_VERSION="/api/v1"
21
+
10
22
  # LaunchDarkly
11
23
  NUXT_PUBLIC_LD_CLIENT_ID=""
12
24
 
13
25
  # Identity Provider
14
26
  NUXT_PUBLIC_IDP_URL="https://dev.loginproxy.gov.bc.ca/auth"
15
27
  NUXT_PUBLIC_IDP_REALM="bcregistry"
16
- NUXT_PUBLIC_IDP_CLIENTID="connect-web"
28
+ NUXT_PUBLIC_IDP_CLIENTID="connect-web"
29
+ NUXT_PUBLIC_SITEMINDER_LOGOUT_URL="https://logontest7.gov.bc.ca/clp-cgi/logoff.cgi"
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @sbc-connect/nuxt-pay
2
2
 
3
+ ## 0.1.8
4
+
5
+ ### Patch Changes
6
+
7
+ - [#36](https://github.com/bcgov/connect-nuxt/pull/36) [`a9176be`](https://github.com/bcgov/connect-nuxt/commit/a9176be460388cba2df53cdfb49e4fd2dfd3d324) Thanks [@kialj876](https://github.com/kialj876)! - Pay Layer fee options update
8
+ Pay Layer documentation
9
+ bcgov/entity#29337
10
+
11
+ - [#32](https://github.com/bcgov/connect-nuxt/pull/32) [`66d83d1`](https://github.com/bcgov/connect-nuxt/commit/66d83d14b2ec7950057dd39a4d876a8c4096923f) Thanks [@kialj876](https://github.com/kialj876)! - Pay layer cleanup bcgov/entity#29337
12
+
13
+ - Updated dependencies [[`b2a0458`](https://github.com/bcgov/connect-nuxt/commit/b2a04587d5408d213d463ef6161b701ca597ef86), [`66d83d1`](https://github.com/bcgov/connect-nuxt/commit/66d83d14b2ec7950057dd39a4d876a8c4096923f)]:
14
+ - @sbc-connect/nuxt-auth@0.1.8
15
+
16
+ ## 0.1.7
17
+
18
+ ### Patch Changes
19
+
20
+ - [#28](https://github.com/bcgov/connect-nuxt/pull/28) [`68af125`](https://github.com/bcgov/connect-nuxt/commit/68af1259b87846f42010026977411481e53ca8fb) Thanks [@kialj876](https://github.com/kialj876)! - Filling out the pay layer. Ticket bcgov/entity#29337
21
+
22
+ - Updated dependencies [[`68af125`](https://github.com/bcgov/connect-nuxt/commit/68af1259b87846f42010026977411481e53ca8fb)]:
23
+ - @sbc-connect/nuxt-auth@0.1.7
24
+
3
25
  ## 0.1.6
4
26
 
5
27
  ### Patch Changes
package/README.md CHANGED
@@ -15,7 +15,7 @@ This package provides the necessary components, composables, and service integra
15
15
  - Composables for interacting with the payment API.
16
16
  - Pre-configured for handling different payment methods (Credit Card, PAD, etc.).
17
17
 
18
- For detailed usage and documentation, please see the [Pay Layer Docs](../../../docs/packages/layers/pay/intro.md).
18
+ For detailed usage and documentation, please see the [Pay Layer Docs](../../../docs/packages/layers/pay/overview.md).
19
19
 
20
20
  ## Usage
21
21
 
@@ -49,8 +49,9 @@ For local development, you will need credentials for the interacting with the Pa
49
49
 
50
50
  ```
51
51
  # .env
52
- NUXT_PUBLIC_PAY_API_URL="https://pay-api-dev.pathfinder.gov.bc.ca/api/v1"
53
- NUXT_PUBLIC_PAY_API_KEY="your-dev-api-key"
52
+ NUXT_PUBLIC_PAY_API_URL="https://test.api.connect.gov.bc.ca/pay-dev"
53
+ NUXT_PUBLIC_PAY_API_VERSION="/api/v1"
54
+ NUXT_PUBLIC_X_API_KEY="your-dev-api-key"
54
55
  ```
55
56
 
56
57
  ### Production Environments
@@ -0,0 +1,2 @@
1
+ /* eslint-disable max-len */
2
+ export default defineAppConfig({})
@@ -0,0 +1,12 @@
1
+ <script setup lang="ts">
2
+ defineProps<{ description: string, fee: number, showFeeValue: boolean }>()
3
+ </script>
4
+
5
+ <template>
6
+ <div class="flex justify-between pl-9 pr-4 py-3">
7
+ <p class="font-bold">
8
+ {{ description }}
9
+ </p>
10
+ <p>{{ showFeeValue ? `$${fee.toFixed(2)}`: '$ -' }}</p>
11
+ </div>
12
+ </template>
@@ -0,0 +1,197 @@
1
+ <script setup lang="ts">
2
+ const { t } = useI18n()
3
+ const {
4
+ feeOptions,
5
+ fees,
6
+ placeholderFeeItem,
7
+ total,
8
+ totalServiceFees,
9
+ totalFutureEffectiveFees,
10
+ totalPriorityFees,
11
+ totalProcessingFees,
12
+ totalGst,
13
+ totalPst,
14
+ userSelectedPaymentMethod,
15
+ allowedPaymentMethods,
16
+ userPaymentAccount,
17
+ allowAlternatePaymentMethod
18
+ } = storeToRefs(useConnectFeeStore())
19
+
20
+ const isPlaceholderActive = ref(false)
21
+
22
+ watch(fees, (v) => {
23
+ if (v && (Object.keys(v).length > 0)) {
24
+ isPlaceholderActive.value = false
25
+ } else {
26
+ isPlaceholderActive.value = true
27
+ }
28
+ }, { immediate: true, deep: true })
29
+
30
+ const feeItems = computed<ConnectFeeItem[]>(() => {
31
+ if (!isPlaceholderActive.value) {
32
+ return Object.values(fees.value)
33
+ }
34
+ return [placeholderFeeItem.value]
35
+ })
36
+
37
+ const serviceFee = computed(() => {
38
+ return isPlaceholderActive.value
39
+ ? placeholderFeeItem.value.serviceFees
40
+ : totalServiceFees.value
41
+ })
42
+
43
+ // folding stuff
44
+ const folded = ref(false)
45
+
46
+ const isFoldable = useMediaQuery('(max-width: 1024px)')
47
+ watch(isFoldable, (val) => {
48
+ if (!val) {
49
+ folded.value = false
50
+ }
51
+ })
52
+
53
+ const toggleFolded = () => {
54
+ if (isFoldable.value) {
55
+ folded.value = !folded.value
56
+ }
57
+ }
58
+
59
+ const getItemFee = (feeItem: ConnectFeeItem) => {
60
+ if (feeItem.isPlaceholder) {
61
+ return '$ -'
62
+ }
63
+ if (feeItem.waived) {
64
+ return t('connect.label.noFee')
65
+ }
66
+ return `$${(feeItem.filingFees * (feeItem.quantity || 1)).toFixed(2)}`
67
+ }
68
+ </script>
69
+
70
+ <template>
71
+ <div
72
+ data-testid="fee-widget"
73
+ class="z-10 rounded bg-white lg:shadow-sm"
74
+ >
75
+ <UButton
76
+ :tabindex="isFoldable ? 0 : -1"
77
+ :role="isFoldable ? 'button' : 'title'"
78
+ class="flex w-full bg-brand py-2 pl-4 text-lg lg:text-3xl font-bold transition-all"
79
+ :class="[folded ? 'rounded' : 'rounded-b-none rounded-t', isFoldable ? '' : 'pointer-events-none']"
80
+ :aria-label="$t('connect.label.feeSummary')"
81
+ :label="$t('connect.label.feeSummary')"
82
+ @click="toggleFolded"
83
+ >
84
+ <template #trailing>
85
+ <div class="flex grow justify-end pr-1">
86
+ <UIcon
87
+ v-if="isFoldable"
88
+ class="size-7"
89
+ :name="folded ? 'i-mdi-chevron-down' : 'i-mdi-chevron-up'"
90
+ />
91
+ </div>
92
+ </template>
93
+ </UButton>
94
+ <ConnectTransitionCollapse>
95
+ <div v-if="!folded">
96
+ <div class="divide-y divide-line-muted pt-1 text-sm">
97
+ <div
98
+ v-for="feeItem in feeItems"
99
+ :key="feeItem.filingTypeCode"
100
+ data-testid="fee-item"
101
+ class="flex justify-between px-4 py-3"
102
+ >
103
+ <div>
104
+ <p class="flex items-center gap-1 font-bold">
105
+ <span>{{ feeItem.label }}</span>
106
+ </p>
107
+ <p
108
+ v-if="feeItem.quantity !== undefined && feeItem.quantityDesc"
109
+ class="pl-4 text-neutral-toned"
110
+ >
111
+ x {{ feeItem.quantity }} {{ feeItem.quantityDesc }}
112
+ </p>
113
+ </div>
114
+ <p>{{ getItemFee(feeItem) }}</p>
115
+ </div>
116
+ <ConnectFeeExtraFee
117
+ v-if="!!feeOptions.showFutureEffectiveFee || (!!feeOptions.showAllActiveFees && totalFutureEffectiveFees)"
118
+ data-testid="future-effective-fee"
119
+ :description="$t('connect.label.futureEffectiveFee')"
120
+ :fee="totalFutureEffectiveFees"
121
+ show-fee-value
122
+ />
123
+ <ConnectFeeExtraFee
124
+ v-if="!!feeOptions.showPriorityFee || (!!feeOptions.showAllActiveFees && totalPriorityFees)"
125
+ data-testid="priority-fee"
126
+ :description="$t('connect.label.priorityFee')"
127
+ :fee="totalPriorityFees"
128
+ show-fee-value
129
+ />
130
+ <ConnectFeeExtraFee
131
+ v-if="!!feeOptions.showProcessingFee || (!!feeOptions.showAllActiveFees && totalProcessingFees)"
132
+ data-testid="processing-fee"
133
+ :description="$t('connect.label.processingFee')"
134
+ :fee="totalProcessingFees"
135
+ show-fee-value
136
+ />
137
+ <ConnectFeeExtraFee
138
+ v-if="!!feeOptions.showServiceFee || (!!feeOptions.showAllActiveFees && serviceFee)"
139
+ data-testid="service-fee"
140
+ :description="$t('connect.label.serviceFee')"
141
+ :fee="serviceFee"
142
+ show-fee-value
143
+ />
144
+ <ConnectFeeExtraFee
145
+ v-if="!!feeOptions.showPst || (!!feeOptions.showAllActiveFees && totalPst)"
146
+ data-testid="pst-fee"
147
+ :description="$t('connect.label.pst')"
148
+ :fee="totalPst"
149
+ show-fee-value
150
+ />
151
+ <ConnectFeeExtraFee
152
+ v-if="!!feeOptions.showGst || (!!feeOptions.showAllActiveFees && totalGst)"
153
+ data-testid="gst-fee"
154
+ :description="$t('connect.label.gst')"
155
+ :fee="totalGst"
156
+ show-fee-value
157
+ />
158
+ </div>
159
+ <div
160
+ data-testid="total-fee"
161
+ class="flex flex-row items-end justify-between border-t border-line-muted p-3"
162
+ >
163
+ <p class="mb-1 font-bold">
164
+ {{ $t("connect.label.totalFees") }}
165
+ </p>
166
+ <p class="flex items-end text-sm text-neutral">
167
+ <span class="mb-1">{{ $t("connect.label.cad") }}</span>
168
+ <b class="ml-[5px] flex items-end text-2xl text-black">
169
+ {{ !isPlaceholderActive ? `$${total.toFixed(2)}` : '$ -' }}
170
+ </b>
171
+ </p>
172
+ </div>
173
+ <USelect
174
+ v-if="allowAlternatePaymentMethod && allowedPaymentMethods.length > 1"
175
+ v-model="userSelectedPaymentMethod"
176
+ :items="allowedPaymentMethods"
177
+ variant="none"
178
+ :content="{ sideOffset: -1 }"
179
+ :ui="{
180
+ base: 'rounded-none px-4 py-2 w-full focus-visible:ring-2 focus-visible:ring-primary',
181
+ content: 'rounded-t-none',
182
+ trailingIcon: 'ml-auto',
183
+ itemTrailingIcon: 'hidden',
184
+ }"
185
+ >
186
+ <span class="text-xs text-left">
187
+ {{
188
+ $t(`connect.payMethod.text.${userSelectedPaymentMethod}`, {
189
+ account: userPaymentAccount?.cfsAccount?.bankAccountNumber },
190
+ )
191
+ }}
192
+ </span>
193
+ </USelect>
194
+ </div>
195
+ </ConnectTransitionCollapse>
196
+ </div>
197
+ </template>
@@ -0,0 +1,6 @@
1
+ export enum ConnectPayCfsStatus {
2
+ ACTIVE = 'ACTIVE',
3
+ PENDING = 'PENDING',
4
+ PENDING_PAD_ACTIVATION = 'PENDING_PAD_ACTIVATION'
5
+ // TODO: fill these out as needed
6
+ }
@@ -0,0 +1,6 @@
1
+ export enum ConnectPayMethod {
2
+ DIRECT_PAY = 'DIRECT_PAY',
3
+ PAD = 'PAD',
4
+ BCOL = 'BCOL',
5
+ JV = 'JV'
6
+ }
@@ -0,0 +1,35 @@
1
+ export interface ConnectTax {
2
+ gst: number
3
+ pst: number
4
+ }
5
+
6
+ export interface ConnectFeeItem {
7
+ filingFees: number
8
+ filingType: string
9
+ filingTypeCode: string
10
+ futureEffectiveFees: number
11
+ priorityFees: number
12
+ processingFees: number
13
+ serviceFees: number
14
+ tax: ConnectTax
15
+ total: number
16
+ label?: string
17
+ isPlaceholder?: boolean
18
+ quantity?: number
19
+ quantityDesc?: string
20
+ waived?: boolean
21
+ }
22
+
23
+ export interface ConnectFeeOptions {
24
+ showAllActiveFees?: boolean
25
+ showFutureEffectiveFee?: boolean
26
+ showPriorityFee?: boolean
27
+ showProcessingFee?: boolean
28
+ showGst?: boolean
29
+ showPst?: boolean
30
+ showServiceFee?: boolean
31
+ }
32
+
33
+ export interface ConnectFees { // this could have multiple mapped feeItems
34
+ [key: string]: ConnectFeeItem
35
+ }
@@ -0,0 +1,21 @@
1
+ export interface ConnectPayAccount {
2
+ accountId: string
3
+ accountName: string
4
+ billable: boolean
5
+ cfsAccount: {
6
+ bankAccountNumber: string
7
+ bankInstitutionNumber: string
8
+ bankTransitNumber: string
9
+ cfsAccountNumber: string
10
+ cfsPartyNumber: string
11
+ cfsSiteNumber: string
12
+ paymentMethod: ConnectPayMethod
13
+ status: ConnectPayCfsStatus
14
+ }
15
+ credit: number
16
+ id: number
17
+ padTosAcceptedBy: string
18
+ padTosAcceptedDate: string
19
+ paymentMethod: ConnectPayMethod
20
+ version: number
21
+ }
@@ -0,0 +1,19 @@
1
+ <template>
2
+ <ConnectLayout>
3
+ <template #header>
4
+ <ConnectHeaderAuth />
5
+ </template>
6
+
7
+ <template #body>
8
+ <div class="flex flex-col lg:flex-row lg:gap-6 grow">
9
+ <div class="grow max-w-full overflow-hidden">
10
+ <slot />
11
+ </div>
12
+
13
+ <div class="shrink-0 lg:w-[300px] lg:static sticky lg:mt-10">
14
+ <ConnectFeeWidget class="sticky lg:top-10" />
15
+ </div>
16
+ </div>
17
+ </template>
18
+ </ConnectLayout>
19
+ </template>
@@ -0,0 +1,28 @@
1
+ export default defineNuxtPlugin((nuxtApp) => {
2
+ const rtc = nuxtApp.$config.public
3
+ const payApiUrl = rtc.payApiUrl + rtc.payApiVersion
4
+ const appName = rtc.appName
5
+ const xApiKey = rtc.xApiKey
6
+
7
+ const api = $fetch.create({
8
+ baseURL: payApiUrl,
9
+ async onRequest({ options }) {
10
+ const auth = useConnectAuth()
11
+ const accountStore = useConnectAccountStore()
12
+
13
+ const token = await auth.getToken()
14
+ const accountId = accountStore.currentAccount.id
15
+
16
+ options.headers.set('Authorization', `Bearer ${token}`)
17
+ options.headers.set('App-Name', appName)
18
+ options.headers.set('X-Apikey', xApiKey)
19
+ options.headers.set('Account-Id', String(accountId))
20
+ }
21
+ })
22
+
23
+ return {
24
+ provide: {
25
+ payApi: api
26
+ }
27
+ }
28
+ })
@@ -0,0 +1,276 @@
1
+ export const useConnectFeeStore = defineStore('connect-pay-fee-store', () => {
2
+ const { $payApi } = useNuxtApp()
3
+ const { t } = useI18n()
4
+ const { baseModal } = useConnectModal()
5
+
6
+ const defaultFeeOptions = {
7
+ showAllActiveFees: true,
8
+ showFutureEffectiveFee: false,
9
+ showPriorityFee: false,
10
+ showProcessingFee: false,
11
+ showGst: false,
12
+ showPst: false,
13
+ showServiceFee: false
14
+ }
15
+ const feeOptions = ref<ConnectFeeOptions>(defaultFeeOptions)
16
+
17
+ const fees = ref<ConnectFees>({})
18
+ const feesCached = ref<ConnectFees>({})
19
+
20
+ const defaultPlaceholder = {
21
+ isPlaceholder: true,
22
+ filingFees: 0,
23
+ filingType: 'placeholder',
24
+ filingTypeCode: 'PLACEHOLDER',
25
+ futureEffectiveFees: 0,
26
+ label: '',
27
+ priorityFees: 0,
28
+ processingFees: 0,
29
+ serviceFees: 0,
30
+ tax: {
31
+ gst: 0,
32
+ pst: 0
33
+ },
34
+ total: 0
35
+ }
36
+ const placeholderFeeItem = ref<ConnectFeeItem>(defaultPlaceholder)
37
+
38
+ const initFees = async (
39
+ feeCodes: { code: string, entityType: string, label: string, quantityDesc?: string }[],
40
+ placeholder: { label: string, matchServiceFeeToCode?: string },
41
+ options?: ConnectFeeOptions
42
+ ) => {
43
+ // Get all the fee information for each fee code from the pay api
44
+ const feePromises = []
45
+ for (const feeInfo of feeCodes) {
46
+ feePromises.push(getFee(feeInfo.entityType, feeInfo.code))
47
+ }
48
+ const feesResolved = (await Promise.all(feePromises)).filter(fee => !!fee)
49
+
50
+ // Add all fee information for each code to the store
51
+ feesCached.value = feesResolved.reduce((reducedFees, fee) => {
52
+ return {
53
+ ...reducedFees,
54
+ [fee.filingTypeCode]: {
55
+ ...fee,
56
+ label: (feeCodes.find(feeInfo => feeInfo.code === fee.filingTypeCode))?.label,
57
+ quantityDesc: (feeCodes.find(feeInfo => feeInfo.code === fee.filingTypeCode))?.quantityDesc
58
+ }
59
+ }
60
+ }, feesCached.value)
61
+
62
+ // set the placeholder values
63
+ placeholderFeeItem.value.label = placeholder.label
64
+ if (placeholder.matchServiceFeeToCode) {
65
+ placeholderFeeItem.value.serviceFees = feesCached.value[placeholder.matchServiceFeeToCode]?.serviceFees || 0
66
+ }
67
+
68
+ // set fee options
69
+ if (options) {
70
+ feeOptions.value = {
71
+ ...feeOptions.value,
72
+ ...options
73
+ }
74
+ }
75
+ }
76
+
77
+ const getTotalFromFees = (feeValue: string, isTax = false) => {
78
+ let total = 0
79
+ for (const key of Object.keys(fees.value)) {
80
+ if (fees.value[key]?.waived) {
81
+ // if waived then total value for is 0
82
+ continue
83
+ }
84
+ const quantity = fees.value[key]?.quantity ?? 1
85
+ // @ts-expect-error - string cant index
86
+ if (isTax && fees.value[key].tax[feeValue]) {
87
+ // @ts-expect-error - string cant index
88
+ total += fees.value[key].tax[feeValue] * quantity
89
+ // @ts-expect-error - string cant index
90
+ } else if (fees.value[key][feeValue]) {
91
+ if (feeValue === 'total') {
92
+ // @ts-expect-error - string cant index
93
+ // ignore service fee and processing fee
94
+ // - (otherwise incorrectly adding it for each item instead of once at the end)
95
+ total += (fees.value[key].total - fees.value[key].serviceFees - fees.value[key].processingFees) * quantity
96
+ } else {
97
+ // @ts-expect-error - string cant index
98
+ total += fees.value[key][feeValue] * quantity
99
+ }
100
+ }
101
+ }
102
+ return total
103
+ }
104
+
105
+ const getMaxFromFees = (feeValue: string) => {
106
+ let maxFee = 0
107
+ for (const key of Object.keys(fees.value)) {
108
+ // @ts-expect-error - string cant index
109
+ const itemFee = fees.value[key][feeValue]
110
+ if (itemFee && (itemFee > maxFee)) {
111
+ maxFee = itemFee
112
+ }
113
+ }
114
+ return maxFee
115
+ }
116
+
117
+ const totalFutureEffectiveFees = computed(() => getTotalFromFees('futureEffectiveFees'))
118
+ const totalPriorityFees = computed(() => getTotalFromFees('priorityFees'))
119
+ const totalProcessingFees = computed(() => getMaxFromFees('processingFees'))
120
+ const totalServiceFees = computed(() => getMaxFromFees('serviceFees'))
121
+ const totalGst = computed(() => getTotalFromFees('gst', true))
122
+ const totalPst = computed(() => getTotalFromFees('pst', true))
123
+ const total = computed(() => getTotalFromFees('total') + totalServiceFees.value + totalProcessingFees.value)
124
+
125
+ /**
126
+ * Fetches the Fee info for the given entity type / fee code combination.
127
+ *
128
+ * @returns {Promise<Fee | undefined>} Fee data or undefined if an error occurs.
129
+ */
130
+ const getFee = async (
131
+ entityType: string,
132
+ code: string
133
+ ): Promise<ConnectFeeItem | undefined> => {
134
+ try {
135
+ const params = {
136
+ priority: true,
137
+ futureEffective: true
138
+ }
139
+ return await $payApi<ConnectFeeItem>(`/fees/${entityType}/${code}`, { params })
140
+ } catch (error) {
141
+ console.error('Error fetching Fee: ', error)
142
+ }
143
+ }
144
+
145
+ const addReplaceFee = (
146
+ code: string,
147
+ options?: {
148
+ futureEffective?: boolean
149
+ priority?: boolean
150
+ quantity?: number
151
+ quantityDesc?: string
152
+ waived?: boolean
153
+ }
154
+ ) => {
155
+ const fee = feesCached.value?.[code]
156
+ if (fee) {
157
+ const futureEffectiveFee = options?.futureEffective ? fee.futureEffectiveFees : 0
158
+ const priorityFee = options?.priority ? fee.priorityFees : 0
159
+ const total = fee.total - (fee.futureEffectiveFees - futureEffectiveFee) - (fee.priorityFees - priorityFee)
160
+ const extraFees = {
161
+ futureEffectiveFees: options?.futureEffective ? fee.futureEffectiveFees : 0,
162
+ priorityFees: options?.priority ? fee.priorityFees : 0,
163
+ total
164
+ }
165
+ fees.value[code] = {
166
+ ...fee,
167
+ ...extraFees,
168
+ ...(options || {})
169
+ }
170
+ return
171
+ }
172
+ console.error(`Error adding ${code}. Please use initFees to initialize this fee code before adding it.`)
173
+ }
174
+
175
+ const removeFee = (code: string) => {
176
+ /* eslint-disable-next-line */
177
+ delete fees.value[code]
178
+ }
179
+
180
+ // alternate payment option stuff
181
+ const PAD_PENDING_STATES = [ConnectPayCfsStatus.PENDING, ConnectPayCfsStatus.PENDING_PAD_ACTIVATION]
182
+ const userPaymentAccount = shallowRef<ConnectPayAccount>({} as ConnectPayAccount)
183
+ const userSelectedPaymentMethod = ref<ConnectPayMethod>(ConnectPayMethod.DIRECT_PAY)
184
+ const allowAlternatePaymentMethod = ref<boolean>(false)
185
+ const allowedPaymentMethods = ref<{ label: string, value: ConnectPayMethod }[]>([])
186
+
187
+ watch(userSelectedPaymentMethod, () => {
188
+ // if pad in confirmation period then set selected payment to CC
189
+ if (PAD_PENDING_STATES.includes(userPaymentAccount.value?.cfsAccount?.status)) {
190
+ userSelectedPaymentMethod.value = ConnectPayMethod.DIRECT_PAY
191
+ // show modal for user
192
+ baseModal.open({
193
+ title: t('connect.label.padAccountInConfirmationPeriod'),
194
+ description: t('connect.text.padAccountInConfirmationPeriod'),
195
+ dismissible: true,
196
+ buttons: [
197
+ { label: t('connect.label.close'), variant: 'outline', shouldClose: true }
198
+ ]
199
+ })
200
+ }
201
+ })
202
+
203
+ const $resetAlternatePayOptions = () => {
204
+ userPaymentAccount.value = {} as ConnectPayAccount
205
+ userSelectedPaymentMethod.value = ConnectPayMethod.DIRECT_PAY
206
+ allowAlternatePaymentMethod.value = false
207
+ allowedPaymentMethods.value = []
208
+ }
209
+
210
+ const initAlternatePaymentMethod = async () => {
211
+ $resetAlternatePayOptions()
212
+ const accountId = useConnectAccountStore().currentAccount.id
213
+ try {
214
+ // get payment account
215
+ const res = await $payApi<ConnectPayAccount>(`/accounts/${accountId}`)
216
+ userPaymentAccount.value = res
217
+
218
+ // add options to allowedPaymentMethods
219
+ let defaultMethod = userPaymentAccount.value.paymentMethod
220
+ if (defaultMethod !== undefined) {
221
+ const accountNum = userPaymentAccount.value.cfsAccount?.bankAccountNumber ?? ''
222
+ allowedPaymentMethods.value.push({
223
+ label: t(`connect.payMethod.label.${defaultMethod}`, { account: accountNum }),
224
+ value: defaultMethod
225
+ })
226
+
227
+ // only add direct pay if not default option
228
+ if (defaultMethod !== ConnectPayMethod.DIRECT_PAY) {
229
+ allowedPaymentMethods.value.push({
230
+ label: t(`connect.payMethod.label.${ConnectPayMethod.DIRECT_PAY}`),
231
+ value: ConnectPayMethod.DIRECT_PAY
232
+ })
233
+ // if pad in confirmation period then set default payment to CC
234
+ if (PAD_PENDING_STATES.includes(res.cfsAccount?.status)) {
235
+ defaultMethod = ConnectPayMethod.DIRECT_PAY
236
+ }
237
+ }
238
+ }
239
+ userSelectedPaymentMethod.value = defaultMethod
240
+
241
+ // only set allowed flag to true if previous steps didnt cause an error
242
+ allowAlternatePaymentMethod.value = true
243
+ } catch (e) {
244
+ logFetchError(e, 'Error initializing user payment account')
245
+ }
246
+ }
247
+
248
+ const $reset = () => {
249
+ feeOptions.value = defaultFeeOptions
250
+ fees.value = {}
251
+ placeholderFeeItem.value = defaultPlaceholder
252
+ $resetAlternatePayOptions()
253
+ }
254
+
255
+ return {
256
+ feeOptions,
257
+ fees,
258
+ placeholderFeeItem,
259
+ totalFutureEffectiveFees,
260
+ totalPriorityFees,
261
+ totalProcessingFees,
262
+ totalGst,
263
+ totalPst,
264
+ totalServiceFees,
265
+ total,
266
+ initFees,
267
+ addReplaceFee,
268
+ removeFee,
269
+ initAlternatePaymentMethod,
270
+ userPaymentAccount,
271
+ userSelectedPaymentMethod,
272
+ allowedPaymentMethods,
273
+ allowAlternatePaymentMethod,
274
+ $reset
275
+ }
276
+ })
@@ -0,0 +1,43 @@
1
+ /* eslint-disable max-len */
2
+ export default {
3
+ connect: {
4
+ label: {
5
+ cad: 'CAD',
6
+ close: 'Close',
7
+ feeSummary: 'Fee Summary',
8
+ futureEffectiveFee: 'Future Effective Fee',
9
+ gst: 'GST',
10
+ noFee: 'No Fee',
11
+ priorityFee: 'Priority Fee',
12
+ processingFee: 'Processing Fee',
13
+ pst: 'PST',
14
+ serviceFee: 'Service Fee',
15
+ totalFees: 'Total Fees',
16
+ padAccountInConfirmationPeriod: 'PAD Account in Confirmation Period'
17
+ },
18
+ payMethod: {
19
+ // These are used dynamically with the ConnectPayMethod enum
20
+ label: {
21
+ BCOL: 'BC Online Account',
22
+ DIRECT_PAY: 'Credit Card',
23
+ EFT: 'Electronic Funds Transfer',
24
+ EJV: 'Electronic Journal Voucher',
25
+ ONLINE_BANKING: 'Online Banking',
26
+ PAD: 'Pre-authorized Debit (PAD) {account}',
27
+ undefined: 'Default'
28
+ },
29
+ text: {
30
+ BCOL: 'Paying with BC Online Account',
31
+ DIRECT_PAY: 'Paying with Credit Card',
32
+ EFT: 'Paying with Electronic Funds Transfer',
33
+ EJV: 'Paying with Electronic Journal Voucher',
34
+ ONLINE_BANKING: 'Paying with Online Banking',
35
+ PAD: 'Paying with Pre-authorized Debit (PAD) {account}',
36
+ undefined: 'Paying with default method'
37
+ }
38
+ },
39
+ text: {
40
+ padAccountInConfirmationPeriod: 'This account will not be able to perform any PAD transactions until the mandatory (3) day confirmation period has ended. Until then you may continue to pay using credit card.'
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,2 @@
1
+ export default {
2
+ }
@@ -0,0 +1,15 @@
1
+ import { defineNuxtModule, createResolver } from 'nuxt/kit'
2
+
3
+ export default defineNuxtModule({
4
+ meta: {
5
+ name: 'pay-assets',
6
+ configKey: 'payAssets'
7
+ },
8
+ defaults: {},
9
+ async setup(_options, _nuxt) {
10
+ console.info('Setting up **pay** assets module')
11
+ const resolver = createResolver(import.meta.url)
12
+
13
+ _nuxt.options.css.push(resolver.resolve('./runtime/assets/connect-pay-tw.css'))
14
+ }
15
+ })
@@ -0,0 +1,2 @@
1
+ @import "#connect-theme";
2
+ @source "../../../../app";
package/nuxt.config.ts CHANGED
@@ -12,9 +12,37 @@ export default defineNuxtConfig({
12
12
 
13
13
  extends: ['@sbc-connect/nuxt-auth'],
14
14
 
15
+ imports: {
16
+ dirs: ['interfaces', 'enums', 'stores']
17
+ },
18
+
15
19
  alias: {
16
20
  '#pay': resolve('./')
17
21
  },
18
22
 
19
- css: [resolve('./app/assets/css/tw-pay.css')]
23
+ i18n: {
24
+ locales: [
25
+ {
26
+ name: 'English',
27
+ code: 'en-CA',
28
+ language: 'en-CA',
29
+ dir: 'ltr',
30
+ file: 'en-CA.ts'
31
+ },
32
+ {
33
+ name: 'Français',
34
+ code: 'fr-CA',
35
+ language: 'fr-CA',
36
+ dir: 'ltr',
37
+ file: 'fr-CA.ts'
38
+ }
39
+ ]
40
+ },
41
+
42
+ runtimeConfig: {
43
+ public: {
44
+ payApiUrl: '',
45
+ payApiVersion: ''
46
+ }
47
+ }
20
48
  })
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sbc-connect/nuxt-pay",
3
3
  "type": "module",
4
- "version": "0.1.6",
4
+ "version": "0.1.8",
5
5
  "repository": "github:bcgov/connect-nuxt",
6
6
  "license": "BSD-3-Clause",
7
7
  "main": "./nuxt.config.ts",
@@ -12,19 +12,19 @@
12
12
  "nuxt": "^4.0.2",
13
13
  "typescript": "^5.8.3",
14
14
  "vue-tsc": "^3.0.4",
15
- "@sbc-connect/eslint-config": "0.0.5",
16
- "@sbc-connect/playwright-config": "0.0.4",
17
- "@sbc-connect/vitest-config": "0.0.5"
15
+ "@sbc-connect/playwright-config": "0.0.6",
16
+ "@sbc-connect/eslint-config": "0.0.6",
17
+ "@sbc-connect/vitest-config": "0.0.6"
18
18
  },
19
19
  "dependencies": {
20
- "@sbc-connect/nuxt-auth": "0.1.6"
20
+ "@sbc-connect/nuxt-auth": "0.1.8"
21
21
  },
22
22
  "scripts": {
23
23
  "preinstall": "npx only-allow pnpm",
24
- "dev": "nuxi dev .playground",
24
+ "dev": "nuxi dev .playground --dotenv ../.env",
25
25
  "build": "nuxt build .playground",
26
26
  "build:test": "pnpm generate && npx serve .playground/.output/public",
27
- "generate": "nuxt generate .playground",
27
+ "generate": "nuxt generate .playground --dotenv ../.env",
28
28
  "preview": "npx serve .playground/.output/public",
29
29
  "lint": "eslint .",
30
30
  "lint:fix": "eslint --fix .",
@@ -1,2 +0,0 @@
1
- @import "#auth/app/assets/css/tw-auth.css";
2
- @source "../../../app/";