stripe-stateful-mock
Version:
A half-baked, stateful Stripe mock server
153 lines (139 loc) • 5.84 kB
text/typescript
import Stripe from "stripe";
import {AccountData} from "./AccountData";
import {generateId} from "./utils";
import {RestError} from "./RestError";
import log = require("loglevel");
export namespace disputes {
const accountDisputes = new AccountData<Stripe.Dispute>();
export function createFromSource(accountId: string, token: string, charge: Stripe.Charge, reverseBalanceTransacton: boolean): Stripe.Dispute {
log.debug("disputes.createFromSource", accountId, token);
// Something like 4 business days at 5pm. May not be exactly right.
const transactionAvailableDate = addBusinessDays(new Date(), 4);
transactionAvailableDate.setHours(17);
transactionAvailableDate.setMinutes(0, 0, 0);
// Something like 7 business days at 4:59:59pm. May not be exactly right.
const evidenceDueDate = addBusinessDays(new Date(), 7);
transactionAvailableDate.setHours(17);
transactionAvailableDate.setMinutes(0, 0, -1);
const disputeId = `dp_${generateId(24)}`;
const disputeTxnId = `txn_${generateId(24)}`;
const balanceTransactions: Stripe.BalanceTransaction[] = [];
if (reverseBalanceTransacton) {
balanceTransactions.push({
id: disputeTxnId,
object: "balance_transaction",
amount: -charge.amount,
available_on: (transactionAvailableDate.getTime() / 1000) | 0,
created: (Date.now() / 1000) | 0,
currency: charge.currency,
description: `Chargeback withdrawal for ${charge.id}`,
exchange_rate: null,
fee: 1500,
fee_details: [
{
amount: 1500,
application: null,
currency: charge.currency,
description: "Dispute fee",
type: "stripe_fee"
}
],
net: -charge.amount - 1500,
reporting_category: "dispute",
source: `dp_${generateId(24)}`,
status: "pending",
type: "adjustment"
});
}
const dispute: Stripe.Dispute = {
id: disputeId,
object: "dispute",
amount: +charge.amount,
balance_transactions: balanceTransactions,
charge: charge.id,
created: (Date.now() / 1000) | 0,
currency: charge.currency,
evidence: {
access_activity_log: null,
billing_address: null,
cancellation_policy: null,
cancellation_policy_disclosure: null,
cancellation_rebuttal: null,
customer_communication: null,
customer_email_address: null,
customer_name: null,
customer_purchase_ip: null,
customer_signature: null,
duplicate_charge_documentation: null,
duplicate_charge_explanation: null,
duplicate_charge_id: null,
product_description: null,
receipt: null,
refund_policy: null,
refund_policy_disclosure: null,
refund_refusal_explanation: null,
service_date: null,
service_documentation: null,
shipping_address: null,
shipping_carrier: null,
shipping_date: null,
shipping_documentation: null,
shipping_tracking_number: null,
uncategorized_file: null,
uncategorized_text: null
},
evidence_details: {
due_by: (evidenceDueDate.getTime() / 1000) | 0,
has_evidence: false,
past_due: false,
submission_count: 0
},
is_charge_refundable: false,
livemode: false,
metadata: {},
network_reason_code: undefined, // I don't see this in actual calls.
payment_intent: null,
reason: "fraudulent",
status: "needs_response"
};
switch (token) {
case "tok_createDispute":
// Default values.
break;
case "tok_createDisputeProductNotReceived":
dispute.reason = "product_not_received";
break;
case "tok_createDisputeInquiry":
dispute.status = "warning_needs_response";
dispute.is_charge_refundable = true;
break;
default:
throw new Error(`Unhandled dispute source token ${token}`);
}
accountDisputes.put(accountId, dispute);
return dispute;
}
export function retrieve(accountId: string, disputeId: string, paramName: string): Stripe.Dispute {
log.debug("dispute.retrieve", accountId, disputeId, paramName);
const dispute = accountDisputes.get(accountId, disputeId);
if (!dispute) {
throw new RestError(404, {
code: "resource_missing",
doc_url: "https://stripe.com/docs/error-codes/resource-missing",
message: `No such dispute: ${disputeId}`,
param: paramName,
type: "invalid_request_error"
});
}
return dispute;
}
/**
* https://gist.github.com/psdtohtml5/7000529
*/
function addBusinessDays(d: Date, n: number): Date {
d = new Date(d.getTime());
const day = d.getDay();
d.setDate(d.getDate() + n + (day === 6 ? 2 : +!day) + (Math.floor((n - 1 + (day % 6 || 1)) / 5) * 2));
return d;
}
}