-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: manual payment gateway support
- Loading branch information
Showing
11 changed files
with
337 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
159 changes: 159 additions & 0 deletions
159
packages/composable-cli/src/commands/payments/manual/manual-command.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
import yargs from "yargs" | ||
|
||
import { CommandContext, CommandHandlerFunction } from "../../../types/command" | ||
import { trackCommandHandler } from "../../../util/track-command-handler" | ||
import { createAuthenticationCheckerMiddleware } from "../../generate/generate-command" | ||
import { PaymentsCommandArguments } from "../payments.types" | ||
import inquirer from "inquirer" | ||
import { isTTY } from "../../../util/is-tty" | ||
import boxen from "boxen" | ||
import ora from "ora" | ||
import { setupManualPaymentGateway } from "./util/setup-epcc-manual-gateway" | ||
import { EPPaymentsForce } from "./util/setup-ep-payments-schema" | ||
import { processUnknownError } from "../../../util/process-unknown-error" | ||
import { checkGateway } from "@elasticpath/composable-common" | ||
import { | ||
ManualCommandArguments, | ||
ManualCommandData, | ||
ManualCommandError, | ||
ManualCommandErrorAlreadyExists, | ||
} from "./manual-integration.types" | ||
|
||
export function createManualPaymentCommand( | ||
ctx: CommandContext, | ||
): yargs.CommandModule<PaymentsCommandArguments, ManualCommandArguments> { | ||
return { | ||
command: "manual", | ||
describe: | ||
"setup EP Payment gateway for your Elastic Path powered storefront", | ||
builder: async (yargs) => { | ||
return yargs | ||
.middleware(createAuthenticationCheckerMiddleware(ctx)) | ||
.option("force", { | ||
type: "boolean", | ||
description: "Force setup of Manual even if already enabled", | ||
}) | ||
.fail(false) | ||
.help() | ||
}, | ||
handler: ctx.handleErrors( | ||
trackCommandHandler(ctx, createManualPaymentCommandHandler), | ||
), | ||
} | ||
} | ||
|
||
export function createManualPaymentCommandHandler( | ||
ctx: CommandContext, | ||
): CommandHandlerFunction< | ||
ManualCommandData, | ||
ManualCommandError, | ||
ManualCommandArguments | ||
> { | ||
return async function manualPaymentCommandHandler(args) { | ||
const spinner = ora() | ||
|
||
const { epClient, logger } = ctx | ||
|
||
try { | ||
if (!epClient) { | ||
spinner.fail(`Failed to setup Manual Payment.`) | ||
return { | ||
success: false, | ||
error: { | ||
code: "missing_ep_client", | ||
message: "Failed to setup Manual Payment - missing EP client", | ||
}, | ||
} | ||
} | ||
|
||
spinner.start(`Checking if Manual gateway already exists...`) | ||
// check if Manual gateway is already setup | ||
if (!args.force) { | ||
const checkGatewayResult = await checkGateway(epClient, "manual") | ||
spinner.stop() | ||
|
||
if (checkGatewayResult.success) { | ||
const forceResult = await resolveForceOptions(args) | ||
|
||
if (!forceResult.force) { | ||
spinner.fail( | ||
`Manual gateway already exists and you didn't want to force an update.`, | ||
) | ||
|
||
logger.warn( | ||
boxen("`Manual was already setup.", { | ||
padding: 1, | ||
borderColor: "yellow", | ||
}), | ||
) | ||
return { | ||
success: false, | ||
error: { | ||
code: "manual_already_setup", | ||
message: "Manual was already setup", | ||
}, | ||
} | ||
} | ||
} | ||
} | ||
|
||
spinner.start(`Setting up Manual gateway...`) | ||
const result = await setupManualPaymentGateway(epClient, logger) | ||
|
||
if (!result.success) { | ||
spinner.fail(`Failed to setup Manual Gateway.`) | ||
return { | ||
success: false, | ||
error: { | ||
code: "manual_gateway_setup_failed", | ||
message: "Failed to setup Manual", | ||
}, | ||
} | ||
} | ||
|
||
spinner.succeed(`Manual setup successfully.`) | ||
|
||
return { | ||
success: true, | ||
data: {}, | ||
} | ||
} catch (e) { | ||
spinner.fail(`Failed to setup Manual gateway.`) | ||
logger.error(processUnknownError(e)) | ||
return { | ||
success: false, | ||
error: { | ||
code: "FAILED_TO_SETUP_MANUAL_GATEWAY", | ||
message: "Failed to setup Manual gateway", | ||
}, | ||
} | ||
} | ||
} | ||
} | ||
|
||
export function isManualGatewayAlreadyExistsError( | ||
error: ManualCommandError, | ||
): error is ManualCommandErrorAlreadyExists { | ||
return error.code === "manual_already_setup" | ||
} | ||
|
||
async function resolveForceOptions( | ||
args: ManualCommandArguments, | ||
): Promise<EPPaymentsForce> { | ||
if (args.interactive && isTTY()) { | ||
const { force } = await inquirer.prompt([ | ||
{ | ||
type: "confirm", | ||
name: "force", | ||
message: "Manual is already enabled would you like update anyway?", | ||
}, | ||
]) | ||
return { | ||
force, | ||
} | ||
} | ||
|
||
throw new Error( | ||
`Invalid arguments: Manual is already enabled and missing force argument`, | ||
) | ||
} |
20 changes: 20 additions & 0 deletions
20
packages/composable-cli/src/commands/payments/manual/manual-integration.types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { PaymentsCommandArguments } from "../payments.types" | ||
|
||
export type ManualCommandData = {} | ||
|
||
export type ManualCommandError = | ||
| { | ||
code: string | ||
message: string | ||
} | ||
| ManualCommandErrorAlreadyExists | ||
|
||
export type ManualCommandErrorAlreadyExists = { | ||
code: "manual_already_setup" | ||
message: string | ||
accountId: string | ||
} | ||
|
||
export type ManualCommandArguments = { | ||
force?: boolean | ||
} & PaymentsCommandArguments |
8 changes: 8 additions & 0 deletions
8
packages/composable-cli/src/commands/payments/manual/util/ep-payments-schema.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { z } from "zod" | ||
|
||
export const manualGatewaySettingsSchema = z.object({ | ||
epPaymentsStripeAccountId: z.string().min(1), | ||
epPaymentsStripePublishableKey: z.string().min(1), | ||
}) | ||
|
||
export type ManualGatewaySettings = z.TypeOf<typeof manualGatewaySettingsSchema> |
14 changes: 14 additions & 0 deletions
14
packages/composable-cli/src/commands/payments/manual/util/setup-ep-payments-schema.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { z } from "zod" | ||
|
||
export const epPaymentsSetupSchema = z.object({ | ||
accountId: z.string(), | ||
publishableKey: z.string(), | ||
}) | ||
|
||
export type EPPaymentsSetup = z.TypeOf<typeof epPaymentsSetupSchema> | ||
|
||
export const epPaymentsForceSchema = z.object({ | ||
force: z.boolean(), | ||
}) | ||
|
||
export type EPPaymentsForce = z.TypeOf<typeof epPaymentsForceSchema> |
51 changes: 51 additions & 0 deletions
51
packages/composable-cli/src/commands/payments/manual/util/setup-epcc-manual-gateway.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { logging } from "@angular-devkit/core" | ||
import type { Gateway, Moltin } from "@moltin/sdk" | ||
import { OperationResult } from "@elasticpath/composable-common" | ||
import { updateManualGateway } from "./update-gateway" | ||
import { processUnknownError } from "../../../../util/process-unknown-error" | ||
|
||
export async function setupManualPaymentGateway( | ||
epccClient: Moltin, | ||
logger: logging.LoggerApi, | ||
): Promise< | ||
OperationResult< | ||
Gateway, | ||
{ | ||
code: "manual_gateway_update_failed" | "unknown" | ||
message: string | ||
} | ||
> | ||
> { | ||
try { | ||
/** | ||
* Update manual gateway to be enabled | ||
*/ | ||
const updateResult = await updateManualGateway(epccClient) | ||
|
||
if (!updateResult.success) { | ||
logger.debug(`Failed to update ep payment gateway.`) | ||
return { | ||
success: false, | ||
error: { | ||
code: "manual_gateway_update_failed", | ||
message: `Failed to update ep payment gateway. ${processUnknownError( | ||
updateResult, | ||
)}`, | ||
}, | ||
} | ||
} | ||
|
||
return updateResult | ||
} catch (err: unknown) { | ||
const errorStr = processUnknownError(err) | ||
logger.error(errorStr) | ||
|
||
return { | ||
success: false, | ||
error: { | ||
code: "unknown", | ||
message: errorStr, | ||
}, | ||
} | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
packages/composable-cli/src/commands/payments/manual/util/update-gateway.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import type { Gateway, Moltin as EpccClient } from "@moltin/sdk" | ||
import { OperationResult } from "@elasticpath/composable-common" | ||
|
||
const errMsg = "Failed to enable manual gateway." | ||
|
||
export async function updateManualGateway( | ||
client: EpccClient, | ||
): Promise<OperationResult<Gateway>> { | ||
try { | ||
const updatedGateway = await client.Gateways.Update("manual", { | ||
enabled: true, | ||
}) | ||
|
||
if (updatedGateway.data) { | ||
return { | ||
success: true, | ||
data: updatedGateway.data, | ||
} | ||
} | ||
|
||
return { | ||
success: false, | ||
error: new Error(`${errMsg} ${JSON.stringify(updatedGateway)}`), | ||
} | ||
} catch (err: unknown) { | ||
return { | ||
success: false, | ||
error: new Error( | ||
`${errMsg} An unknown error occurred ${ | ||
err instanceof Error | ||
? `${err.name} - ${err.message}` | ||
: "Failed to render error." | ||
}`, | ||
), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.