payment-helpers.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. import { ID } from '@vendure/common/lib/shared-types';
  2. import {
  3. ChannelService,
  4. ErrorResult,
  5. OrderService,
  6. PaymentService,
  7. RequestContext,
  8. assertFound,
  9. } from '@vendure/core';
  10. import { SimpleGraphQLClient, TestServer } from '@vendure/testing';
  11. import gql from 'graphql-tag';
  12. import { CREATE_COUPON, REFUND_ORDER } from './graphql/admin-queries';
  13. import {
  14. RefundFragment,
  15. RefundOrderMutation,
  16. RefundOrderMutationVariables,
  17. } from './graphql/generated-admin-types';
  18. import {
  19. GetShippingMethodsQuery,
  20. SetShippingMethodMutation,
  21. SetShippingMethodMutationVariables,
  22. TestOrderFragmentFragment,
  23. TransitionToStateMutation,
  24. TransitionToStateMutationVariables,
  25. } from './graphql/generated-shop-types';
  26. import {
  27. GET_ELIGIBLE_SHIPPING_METHODS,
  28. SET_SHIPPING_ADDRESS,
  29. SET_SHIPPING_METHOD,
  30. TRANSITION_TO_STATE,
  31. } from './graphql/shop-queries';
  32. export async function setShipping(shopClient: SimpleGraphQLClient): Promise<void> {
  33. const { setOrderShippingAddress: order } = await shopClient.query(SET_SHIPPING_ADDRESS, {
  34. input: {
  35. fullName: 'name',
  36. streetLine1: '12 the street',
  37. city: 'Leeuwarden',
  38. postalCode: '123456',
  39. countryCode: 'AT',
  40. },
  41. });
  42. const { eligibleShippingMethods } = await shopClient.query<GetShippingMethodsQuery>(
  43. GET_ELIGIBLE_SHIPPING_METHODS,
  44. );
  45. if (!eligibleShippingMethods?.length) {
  46. throw Error(
  47. `No eligible shipping methods found for order '${String(order.code)}' with a total of '${String(order.totalWithTax)}'`,
  48. );
  49. }
  50. await shopClient.query<SetShippingMethodMutation, SetShippingMethodMutationVariables>(
  51. SET_SHIPPING_METHOD,
  52. {
  53. id: eligibleShippingMethods[1].id,
  54. },
  55. );
  56. }
  57. export async function proceedToArrangingPayment(shopClient: SimpleGraphQLClient): Promise<ID> {
  58. await setShipping(shopClient);
  59. const { transitionOrderToState } = await shopClient.query<
  60. TransitionToStateMutation,
  61. TransitionToStateMutationVariables
  62. >(TRANSITION_TO_STATE, { state: 'ArrangingPayment' });
  63. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  64. return (transitionOrderToState as TestOrderFragmentFragment)!.id;
  65. }
  66. export async function refundOrderLine(
  67. adminClient: SimpleGraphQLClient,
  68. orderLineId: string,
  69. quantity: number,
  70. paymentId: string,
  71. adjustment: number,
  72. ): Promise<RefundFragment> {
  73. const { refundOrder } = await adminClient.query<RefundOrderMutation, RefundOrderMutationVariables>(
  74. REFUND_ORDER,
  75. {
  76. input: {
  77. lines: [{ orderLineId, quantity }],
  78. shipping: 0,
  79. adjustment,
  80. paymentId,
  81. },
  82. },
  83. );
  84. return refundOrder as RefundFragment;
  85. }
  86. /**
  87. * Add a partial payment to an order. This happens, for example, when using Gift cards
  88. */
  89. export async function addManualPayment(server: TestServer, orderId: ID, amount: number): Promise<void> {
  90. const ctx = new RequestContext({
  91. apiType: 'admin',
  92. isAuthorized: true,
  93. authorizedAsOwnerOnly: false,
  94. channel: await server.app.get(ChannelService).getDefaultChannel(),
  95. });
  96. const order = await assertFound(server.app.get(OrderService).findOne(ctx, orderId));
  97. // tslint:disable-next-line:no-non-null-assertion
  98. await server.app.get(PaymentService).createManualPayment(ctx, order, amount, {
  99. method: 'Gift card',
  100. orderId: order.id,
  101. metadata: {
  102. bogus: 'test',
  103. },
  104. });
  105. }
  106. /**
  107. * Create a coupon with the given code and discount amount.
  108. */
  109. export async function createFixedDiscountCoupon(
  110. adminClient: SimpleGraphQLClient,
  111. amount: number,
  112. couponCode: string,
  113. ): Promise<void> {
  114. const { createPromotion } = await adminClient.query(CREATE_COUPON, {
  115. input: {
  116. conditions: [],
  117. actions: [
  118. {
  119. code: 'order_fixed_discount',
  120. arguments: [
  121. {
  122. name: 'discount',
  123. value: String(amount),
  124. },
  125. ],
  126. },
  127. ],
  128. couponCode,
  129. startsAt: null,
  130. endsAt: null,
  131. perCustomerUsageLimit: null,
  132. usageLimit: null,
  133. enabled: true,
  134. translations: [
  135. {
  136. languageCode: 'en',
  137. name: `Coupon ${couponCode}`,
  138. description: '',
  139. customFields: {},
  140. },
  141. ],
  142. customFields: {},
  143. },
  144. });
  145. if (createPromotion.__typename === 'ErrorResult') {
  146. throw new Error(`Error creating coupon: ${(createPromotion as ErrorResult).errorCode}`);
  147. }
  148. }
  149. /**
  150. * Create a coupon that discounts the shipping costs
  151. */
  152. export async function createFreeShippingCoupon(
  153. adminClient: SimpleGraphQLClient,
  154. couponCode: string,
  155. ): Promise<void> {
  156. const { createPromotion } = await adminClient.query(CREATE_COUPON, {
  157. input: {
  158. conditions: [],
  159. actions: [
  160. {
  161. code: 'free_shipping',
  162. arguments: [],
  163. },
  164. ],
  165. couponCode,
  166. startsAt: null,
  167. endsAt: null,
  168. perCustomerUsageLimit: null,
  169. usageLimit: null,
  170. enabled: true,
  171. translations: [
  172. {
  173. languageCode: 'en',
  174. name: `Coupon ${couponCode}`,
  175. description: '',
  176. customFields: {},
  177. },
  178. ],
  179. customFields: {},
  180. },
  181. });
  182. if (createPromotion.__typename === 'ErrorResult') {
  183. throw new Error(`Error creating coupon: ${(createPromotion as ErrorResult).errorCode}`);
  184. }
  185. }
  186. export const CREATE_MOLLIE_PAYMENT_INTENT = gql`
  187. mutation createMolliePaymentIntent($input: MolliePaymentIntentInput!) {
  188. createMolliePaymentIntent(input: $input) {
  189. ... on MolliePaymentIntent {
  190. url
  191. }
  192. ... on MolliePaymentIntentError {
  193. errorCode
  194. message
  195. }
  196. }
  197. }
  198. `;
  199. export const CREATE_STRIPE_PAYMENT_INTENT = gql`
  200. mutation createStripePaymentIntent {
  201. createStripePaymentIntent
  202. }
  203. `;
  204. export const GET_MOLLIE_PAYMENT_METHODS = gql`
  205. query molliePaymentMethods($input: MolliePaymentMethodsInput!) {
  206. molliePaymentMethods(input: $input) {
  207. id
  208. code
  209. description
  210. minimumAmount {
  211. value
  212. currency
  213. }
  214. maximumAmount {
  215. value
  216. currency
  217. }
  218. image {
  219. size1x
  220. size2x
  221. svg
  222. }
  223. }
  224. }
  225. `;