collect_paypal_past_due_invoice.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. const RecurlyWrapper = require('../../app/src/Features/Subscription/RecurlyWrapper')
  2. const async = require('async')
  3. const minimist = require('minimist')
  4. const slowCallback = (callback, error, data) =>
  5. setTimeout(() => callback(error, data), 80)
  6. const handleAPIError = (source, id, error, callback) => {
  7. console.warn(`Errors in ${source} with id=${id}`, error)
  8. if (typeof error === 'string' && error.match(/429$/)) {
  9. return setTimeout(callback, 1000 * 60 * 5)
  10. }
  11. slowCallback(callback)
  12. }
  13. const attemptInvoiceCollection = (invoice, callback) => {
  14. isAccountUsingPaypal(invoice, (error, isPaypal) => {
  15. if (error || !isPaypal) {
  16. return callback(error)
  17. }
  18. const accountId = invoice.account.url.match(/accounts\/(.*)/)[1]
  19. if (USERS_COLLECTED.indexOf(accountId) > -1) {
  20. console.warn(`Skipping duplicate user ${accountId}`)
  21. return callback()
  22. }
  23. INVOICES_COLLECTED.push(invoice.invoice_number)
  24. USERS_COLLECTED.push(accountId)
  25. if (DRY_RUN) {
  26. return callback()
  27. }
  28. RecurlyWrapper.attemptInvoiceCollection(
  29. invoice.invoice_number,
  30. (error, response) => {
  31. if (error) {
  32. return handleAPIError(
  33. 'attemptInvoiceCollection',
  34. invoice.invoice_number,
  35. error,
  36. callback
  37. )
  38. }
  39. INVOICES_COLLECTED_SUCCESS.push(invoice.invoice_number)
  40. slowCallback(callback, null)
  41. }
  42. )
  43. })
  44. }
  45. const isAccountUsingPaypal = (invoice, callback) => {
  46. const accountId = invoice.account.url.match(/accounts\/(.*)/)[1]
  47. RecurlyWrapper.getBillingInfo(accountId, (error, response) => {
  48. if (error) {
  49. return handleAPIError('billing info', accountId, error, callback)
  50. }
  51. if (response.billing_info.paypal_billing_agreement_id) {
  52. return slowCallback(callback, null, true)
  53. }
  54. slowCallback(callback, null, false)
  55. })
  56. }
  57. const attemptInvoicesCollection = callback => {
  58. RecurlyWrapper.getPaginatedEndpoint(
  59. 'invoices',
  60. { state: 'past_due' },
  61. (error, invoices) => {
  62. console.log('invoices', invoices.length)
  63. if (error) {
  64. return callback(error)
  65. }
  66. async.eachSeries(invoices, attemptInvoiceCollection, callback)
  67. }
  68. )
  69. }
  70. const argv = minimist(process.argv.slice(2))
  71. const DRY_RUN = argv.n !== undefined
  72. const INVOICES_COLLECTED = []
  73. const INVOICES_COLLECTED_SUCCESS = []
  74. const USERS_COLLECTED = []
  75. attemptInvoicesCollection(error => {
  76. if (error) {
  77. throw error
  78. }
  79. console.log(
  80. `DONE (DRY_RUN=${DRY_RUN}). ${INVOICES_COLLECTED.length} invoices collection attempts for ${USERS_COLLECTED.length} users. ${INVOICES_COLLECTED_SUCCESS.length} successful collections`
  81. )
  82. console.dir(
  83. {
  84. INVOICES_COLLECTED,
  85. INVOICES_COLLECTED_SUCCESS,
  86. USERS_COLLECTED,
  87. },
  88. { maxArrayLength: null }
  89. )
  90. if (INVOICES_COLLECTED_SUCCESS === 0) {
  91. process.exit(1)
  92. } else {
  93. process.exit()
  94. }
  95. })