Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for addition of sales tax by zip code, Truck History Report form(s) #674

Draft
wants to merge 61 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
0c116fd
Merge pull request #571 from B77Mills/relatedInjectionStaging
B77Mills Jul 21, 2023
2f9e7e8
Include marko-web-leaders in TPS deps
Shinsina Jul 26, 2023
fc9c94c
Include styling for company pages TPS
Shinsina Jul 26, 2023
48683b9
Include Leaders Browser definition
Shinsina Jul 26, 2023
431be55
Utilize company page specific query fragment
Shinsina Jul 26, 2023
b15f9a4
Add company logo and leaders-details components
Shinsina Jul 26, 2023
9f4baba
Import company details Marko.json
Shinsina Jul 26, 2023
00e18fe
Update company page layout TPS
Shinsina Jul 26, 2023
09b6e99
Merge branch 'staging' into staging-tps-company-pages
Shinsina Jul 26, 2023
0077bf9
Merge pull request #575 from Shinsina/staging-tps-company-pages
jwade1327 Jul 26, 2023
b23f0e7
Merge branch 'master' of https://github.com/parameter1/website-randal…
solocommand Aug 14, 2023
deb4f40
Merge pull request #580 from parameter1/rigdig
solocommand Aug 14, 2023
11acb24
Merge pull request #582 from parameter1/rigdig
solocommand Aug 15, 2023
94168c0
Merge branch 'staging' into abNewsletter
B77Mills Aug 17, 2023
081e38c
Merge pull request #587 from B77Mills/abNewsletter
brandonbk Aug 17, 2023
685e6f2
Merge branch 'master' of https://github.com/parameter1/randall-reilly…
B77Mills Aug 23, 2023
5da7f2e
Merge branch 'master' of https://github.com/parameter1/website-randal…
solocommand Aug 30, 2023
5ce1fe4
Merge branch 'master' of https://github.com/parameter1/randall-reilly…
B77Mills Nov 22, 2023
4b59819
Merge branch 'master' of https://github.com/parameter1/randall-reilly…
B77Mills Nov 22, 2023
d15eab7
Merge branch 'master' of https://github.com/parameter1/randall-reilly…
B77Mills Nov 27, 2023
e950838
Pass through user postal code to RigDig Widget
Shinsina Nov 27, 2023
4d9bc1c
Pass through zip to checkout-modal
Shinsina Nov 27, 2023
79ce89c
Permit zip in checkout step 1, calculate sales tax
Shinsina Nov 27, 2023
6d3063e
Display sales tax and total when applicable
Shinsina Nov 27, 2023
d1abf6f
Calculate Sales Tax utility function
Shinsina Nov 27, 2023
da35cf2
Execute util and ensure postal code is set
Shinsina Nov 27, 2023
823755a
Include salesTax in postalCode transaction submit
Shinsina Nov 27, 2023
9675d3a
Merge branch 'master' of https://github.com/parameter1/randall-reilly…
B77Mills Nov 27, 2023
67ad485
Merge branch 'master' of https://github.com/parameter1/randall-reilly…
B77Mills Nov 27, 2023
0702acf
Utilize environment variables for Avatax API
Shinsina Nov 28, 2023
78156cf
Create utility for pretax amount
Shinsina Nov 28, 2023
5e185db
Utilize environment and util for salesTax calc
Shinsina Nov 28, 2023
47e4e15
Pass amount, createTransaction client method call
Shinsina Nov 28, 2023
f3b20da
Utilize amount input for createTransaction request
Shinsina Nov 28, 2023
7145b79
Passthrough pretaxAmount to components
Shinsina Nov 28, 2023
2c35654
Merge branch 'staging' into sales-tax
Shinsina Nov 28, 2023
a3bd996
Merge branch 'master' of https://github.com/parameter1/randall-reilly…
B77Mills Nov 29, 2023
d44c550
Merge branch 'master' of https://github.com/parameter1/randall-reilly…
B77Mills Nov 30, 2023
7d31f34
Merge branch 'master' of https://github.com/parameter1/randall-reilly…
B77Mills Dec 1, 2023
47698bd
Merge branch 'master' of https://github.com/parameter1/randall-reilly…
B77Mills Dec 1, 2023
dadcebd
Merge branch 'staging' into sales-tax
Shinsina Dec 4, 2023
88e3ae5
Merge pull request #675 from Shinsina/sales-tax
brandonbk Dec 4, 2023
fa1d751
Merge pull request #685 from B77Mills/PartnerInsights
B77Mills Dec 4, 2023
db62326
Merge branch 'master' of https://github.com/parameter1/randall-reilly…
B77Mills Dec 7, 2023
5168f69
Merge branch 'master' of https://github.com/parameter1/randall-reilly…
B77Mills Dec 7, 2023
3ec0232
Correct pre-tax amount to 34.95
Shinsina Dec 7, 2023
ab5d8c5
Assert 2 decimal places on total calculation
Shinsina Dec 7, 2023
9c48d1d
Assure correct total is displayed
Shinsina Dec 7, 2023
2ee159a
Merge pull request #689 from Shinsina/sales-tax
B77Mills Dec 7, 2023
adacc5b
Send in correctly truncated transaction amount
Shinsina Dec 29, 2023
1e70566
Assert amount as number
Shinsina Dec 29, 2023
9c94982
Use alternative endpoint to calculate sales tax
Shinsina Dec 29, 2023
bca86c6
Apply taxCode for digital documentation
Shinsina Dec 29, 2023
9eea175
Merge branch 'staging' into sales-tax
Shinsina Dec 29, 2023
6f0a904
Remove stray console.log
Shinsina Dec 29, 2023
7945638
Include styling for country form field
Shinsina Jan 15, 2024
e96c006
Include country, show zip when applicable
Shinsina Jan 15, 2024
4643bc0
Use provided zip when available, otherwise use pre-tax value
Shinsina Jan 15, 2024
c2c882c
Pass through country code where applicable
Shinsina Jan 15, 2024
545e9d5
Prepopulate with US country selected by default
Shinsina Jan 15, 2024
484baa9
Merge branch 'master' into sales-tax
B77Mills Dec 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ services:
PAYFABRIC_GATEWAY_NAME: ${PAYFABRIC_GATEWAY_NAME-EVO US_CC}
PAYFABRIC_ENV: ${PAYFABRIC_ENV-SANDBOX}
PAYFABRIC_PAYMENT_METHODS: ${PAYFABRIC_PAYMENT_METHODS-CreditCard}
AVATAX_API_HOST: ${AVATAX_API_HOST-https://sandbox-rest.avatax.com}
AVATAX_HASHED_CREDENTIALS: ${AVATAX_HASHED_CREDENTIALS}
SENDGRID_API_KEY: ${SENDGRID_API_KEY}
SENDGRID_DEV_TO: ${[email protected]}
DEBUG: rigdig,payfabric,sendgrid
Expand All @@ -203,6 +205,8 @@ services:
PAYFABRIC_GATEWAY_NAME: ${PAYFABRIC_GATEWAY_NAME-EVO US_CC}
PAYFABRIC_ENV: ${PAYFABRIC_ENV-SANDBOX}
PAYFABRIC_PAYMENT_METHODS: ${PAYFABRIC_PAYMENT_METHODS-CreditCard}
AVATAX_API_HOST: ${AVATAX_API_HOST-https://sandbox-rest.avatax.com}
AVATAX_HASHED_CREDENTIALS: ${AVATAX_HASHED_CREDENTIALS}
SENDGRID_API_KEY: ${SENDGRID_API_KEY}
SENDGRID_DEV_TO: ${[email protected]}
DEBUG: rigdig,payfabric,sendgrid
Expand Down
4 changes: 2 additions & 2 deletions packages/payfabric/src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,12 @@ module.exports = class ApiClient {
* @param {IdentityXUserContext} args.user
* @param {String} args.vin @todo memo/note?
*/
async createTransaction({ user, vin }) {
async createTransaction({ user, vin, amount }) {
return this.request({
endpoint: '/payment/api/transaction/create',
body: JSON.stringify({
// @todo additional details, customer reference?
Amount: 34.99,
Amount: amount,
Currency: 'USD',
Customer: user.id || user.email,
SetupId: this.gatewayName,
Expand Down
2 changes: 2 additions & 0 deletions packages/payfabric/src/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ module.exports = cleanEnv(process.env, {
PAYFABRIC_GATEWAY_NAME: str({ desc: 'The name of the PayFabric Gateway to use.', default: 'EVO US_CC' }),
PAYFABRIC_ENV: str({ desc: 'The Payfabric environment', choices: ['SANDBOX', 'LIVE'], default: 'SANDBOX' }),
PAYFABRIC_PAYMENT_METHODS: str({ desc: 'A comma-separated list of enabled payment methods.', default: 'CreditCard,ApplePay,GooglePay' }),
AVATAX_API_HOST: str({ desc: 'The Avatax API host', default: 'https://sandbox-rest.avatax.com' }),
AVATAX_HASHED_CREDENTIALS: str({ desc: 'Base64 encoded credentials for the Avatax API' }),
});
25 changes: 22 additions & 3 deletions packages/payfabric/src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const { asyncRoute } = require('@parameter1/base-cms-utils');
const { json } = require('express');
const pretaxAmount = require('./utils/pre-tax-amount');
const calculateSalesTax = require('./utils/calculate-sales-tax');

const PayFabricAPIClient = require('./client');
const {
Expand All @@ -20,6 +22,8 @@ const createError = (message, code) => {
return error;
};

const countryCodesRequireZip = new Set(['US', 'CA']);

/**
* @typedef ResponseContext
* @prop {import('@parameter1/base-cms-marko-web-identity-x/service')} identityX
Expand All @@ -39,19 +43,34 @@ module.exports = (app) => {
app.post('/__payfabric/create-transaction-token', json(), asyncRoute(async (req, res) => {
try {
const { body } = await req;
const { vin, email } = body;
const {
vin,
countryCode,
email,
zip: postalCode,
} = body;
if (!vin) throw createError('You must provide a VIN to continue.', 400);
if (!email) throw createError('You must provide an email address to continue.', 400);
if (!postalCode && countryCodesRequireZip.has(countryCode)) throw createError('You must provide a zip code to continue', 400);

/** @type {ResponseContext} */
const { identityX } = res.locals;
/** @type {IdentityXContext} */
const ctx = await identityX.loadActiveContext();
const user = ctx.hasUser ? ctx.user : { email };
// Ensure a postalCode is provided even if existing user record doesn't have one
if (!user.postalCode && postalCode) user.postalCode = postalCode;
// Ensure a countryCode is provided even if existing user record doesn't have one
if (!user.countryCode && countryCode) user.countryCode = countryCode;

const { Key } = await client.createTransaction({ user, vin });
const salesTax = countryCodesRequireZip.has(user.countryCode) ? await calculateSalesTax({
postalCode,
pretaxAmount,
}) : 0;
const amount = Number((pretaxAmount + salesTax).toFixed(2));
const { Key } = await client.createTransaction({ user, vin, amount });
const { Token } = await client.createJWT({ transactionId: Key });
res.json({ Token });
res.json({ Token, salesTax });
} catch (error) {
res.status(error.code || 500).json({ error: error.message });
}
Expand Down
35 changes: 35 additions & 0 deletions packages/payfabric/src/utils/calculate-sales-tax.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const fetch = require('node-fetch');
const { AVATAX_API_HOST, AVATAX_HASHED_CREDENTIALS } = require('../env');

module.exports = async ({ postalCode, pretaxAmount }) => {
const now = new Date();
const request = await fetch(`${AVATAX_API_HOST}/api/v2/transactions/create`, {
method: 'POST',
headers: {
'content-type': 'application-json',
Authorization: `Basic ${AVATAX_HASHED_CREDENTIALS}`,
},
body: JSON.stringify({
lines: [
{
quantity: 1,
amount: pretaxAmount,
// https://taxcode.avatax.avalara.com/search?q=DD040000
taxCode: 'DD040000',
},
],
date: `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`,
customerCode: 'parameter1-website-customer',
addresses: {
singleLocation: {
postalCode,
},
},
currencyCode: 'USD',
}),
});
if (!request.ok) throw new Error('Bad fetch response, AvaTax');
const { totalTax } = await request.json();
// totalTax is the amount of tax applied for this transaction
return Number(totalTax);
};
1 change: 1 addition & 0 deletions packages/payfabric/src/utils/pre-tax-amount.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = 34.95;
32 changes: 31 additions & 1 deletion packages/rigdig/browser/checkout-header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,23 @@
1 Truck History Report
</span>
<strong>
$34.99
${{ pretaxAmount }}
</strong>
</div>
<div v-if="salesTax" class="rigdig-modal__promo-footer">
<span>
Sales Tax
</span>
<strong>
${{ salesTax }}
</strong>
</div>
<div v-if="salesTax" class="rigdig-modal__promo-footer">
<span>
<b>Total</b>
</span>
<strong>
${{ total }}
</strong>
</div>
<div v-if="email" class="rigdig-modal__teaser border">
Expand All @@ -52,6 +68,14 @@ export default {
type: Number,
default: 1,
},
salesTax: {
type: Number,
default: null,
},
pretaxAmount: {
type: Number,
default: null,
},
truckInfo: {
type: String,
required: true,
Expand All @@ -71,5 +95,11 @@ export default {
},

emits: ['back'],

computed: {
total() {
return (this.salesTax + this.pretaxAmount).toFixed(2);
},
},
};
</script>
75 changes: 72 additions & 3 deletions packages/rigdig/browser/checkout-modal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
{{ vin }}
</dd>
<dd class="small">
$34.99
${{ total }}
</dd>
</dl>
</div>
Expand Down Expand Up @@ -57,6 +57,8 @@
</div>
<div v-else-if="transactionId" class="rigdig-modal__content">
<checkout-header
:sales-tax="salesTax"
:pretax-amount="pretaxAmount"
:truck-info="truckInfo"
:vin="vin"
title="Sending Report!"
Expand Down Expand Up @@ -103,6 +105,8 @@
</div>
<div v-else class="rigdig-modal__content">
<checkout-header
:sales-tax="salesTax"
:pretax-amount="pretaxAmount"
:truck-info="truckInfo"
:vin="vin"
title="Report found!"
Expand Down Expand Up @@ -157,6 +161,38 @@
>
</template>
</label>
<country-code
v-model="userCountryCode"
class-name="rigdig-modal__form-group"
:required="true"
label="Country"
/>
<label v-if="zipRequired" class="rigdig-modal__label">
<template v-if="zip">
<div class="rigdig-widget__label-text">
Postal/Zip Code <strong class="text-danger">*</strong>
</div>
<input
ref="zip"
:value="zip"
class="form-control rigdig-modal__zip"
type="text"
required
>
</template>
<template v-else>
<div class="rigdig-widget__label-text">
Postal/Zip Code <strong class="text-danger">*</strong>
</div>
<input
ref="zip"
v-model="userZip"
class="form-control rigdig-modal__zip"
type="text"
required
>
</template>
</label>
</div>

<div class="rigdig-modal__buttons">
Expand All @@ -183,7 +219,8 @@
</form>
<alert-error v-if="error" :show-help="false" title="Unable to start checkout.">
<p>
The email address you supplied is invalid. Please verify and try again or
The email address or zip code you supplied is invalid.
Please verify and try again or
<a :href="`mailto:${supportEmail}`">contact us</a>.
</p>
</alert-error>
Expand All @@ -208,6 +245,7 @@
<script>
import IconX from '@parameter1/base-cms-marko-web-icons/browser/x.vue';
import IconCheckCircle from '@parameter1/base-cms-marko-web-icons/browser/check-circle.vue';
import CountryCode from '@parameter1/base-cms-marko-web-identity-x/browser/form/fields/country.vue';
import AlertError from './alert-error.vue';
import CheckoutHeader from './checkout-header.vue';

Expand All @@ -217,15 +255,24 @@ export default {
components: {
AlertError,
CheckoutHeader,
CountryCode,
IconX,
IconCheckCircle,
},

props: {
countryCode: {
type: String,
default: null,
},
email: {
type: String,
default: null,
},
zip: {
type: String,
default: null,
},
buttonLabel: {
type: String,
default: 'Start checkout',
Expand All @@ -249,6 +296,10 @@ export default {
type: Array,
default: () => ['CreditCard', 'ApplePay'],
},
pretaxAmount: {
type: Number,
default: null,
},
debug: {
type: Boolean,
default: false,
Expand All @@ -262,10 +313,13 @@ export default {
emits: ['cancel', 'purchase', 'error', 'generate'],

data: () => ({
userCountryCode: 'US',
userEmail: null,
userZip: null,
error: null,
loading: false,
complete: false,
salesTax: null,
transactionToken: null,
transactionId: null,
client: null,
Expand All @@ -276,12 +330,24 @@ export default {
title() {
return this.complete ? 'Payment Received!' : 'Report Found!';
},
total() {
return (this.salesTax + this.pretaxAmount).toFixed(2);
},
zipRequired() {
return new Set(['US', 'CA']).has(this.userCountryCode);
},
},

created() {
if (this.email) {
this.userEmail = this.email;
}
if (this.zip) {
this.userZip = this.zip;
}
if (this.countryCode) {
this.userCountryCode = this.countryCode;
}
},

methods: {
Expand Down Expand Up @@ -326,7 +392,9 @@ export default {
headers: { 'content-type': 'application/json; charset=utf-8' },
body: JSON.stringify({
vin: this.vin,
countryCode: this.userCountryCode,
email: this.userEmail,
zip: this.userZip,
}),
});
if (!response.ok) {
Expand All @@ -341,7 +409,8 @@ export default {
error.code = response.status;
throw error;
}
const { Token } = await response.json();
const { Token, salesTax } = await response.json();
this.salesTax = salesTax;
return Token;
},

Expand Down
Loading
Loading