Stripe issues after changing currency from CAD to USD

Ghost version 4.50
Node: v14.16.1
OS: Ubuntu 20.04

Looking at my dashboard, it seems as though no payments are coming in.

But looking at Stripe, everything is fine.

The MRR chart was working at some point, and I don’t know when it stopped. Things that have happened in the meantime: Substack disconnected from my Stripe account, then I had to reconnect them so they could do it again because they forgot to remove their commission the first time. Also I’ve upgraded Ghost a couple of times.

When I look at the members in Ghost who have paid their subscription over the past couple of days, everything looks correctly updated. It’s only the MRR chart in the dashboard that’s out of whack, as far as I can see. But I am worried there might be some other problem that’s not obvious yet.

I’m not sure how to try and debug this. Any suggestions?

Still trying to figure this out. The error log is full of messages like the one below, which seem to come from the Admin client, although I don’t know if it’s related. Anyone seen this before?

{
     "name":"Log",
     "hostname":"myhostname",
     "pid":1210,
     "level":50,
     "req":{
        "meta":{
           "requestId":"8baca982-1670-4d19-884e-e7aed3bf369f",
           "userId":"605f91aa7869d305efd920d9"
        },
        "url":"/notifications/",
        "method":"GET",
        "originalUrl":"/ghost/api/canary/admin/notifications/",
        "params":{
           
        },
        "headers":{
           "x-forwarded-for":"216.208.210.147",
           "x-forwarded-proto":"https",
           "x-real-ip":"216.208.210.147",
           "host":"mydomain.com",
           "connection":"close",
           "accept":"application/json, text/javascript, */*; q=0.01",
           "dnt":"1",
           "x-requested-with":"XMLHttpRequest",
           "x-ghost-version":"4.5",
           "app-pragma":"no-cache",
           "user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36",
           "content-type":"application/json; charset=UTF-8",
           "sec-fetch-site":"same-origin",
           "sec-fetch-mode":"cors",
           "sec-fetch-dest":"empty",
           "referer":"https://mydomain.com/ghost/",
           "accept-encoding":"gzip, deflate, br",
           "accept-language":"en-GB,en-US;q=0.9,en;q=0.8",
           "cookie":"**REDACTED**"
        },
        "query":{
           
        }
     },
     "res":{
        "_headers":{
           "x-powered-by":"Express",
           "cache-control":"no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
           "content-type":"application/json; charset=utf-8",
           "content-length":"259",
           "etag":"W/\"103-ztj2XPieAO4mu7ads8IExoZ6hhE\"",
           "vary":"Accept-Encoding"
        },
        "statusCode":500,
        "responseTime":"22ms"
     },
     "err":{
        "id":"1f1c4200-b50d-11eb-abde-6fe45ee69714",
        "domain":"https://mydomain.com",
        "code":null,
        "name":"InternalServerError",
        "statusCode":500,
        "level":"normal",
        "message":"allNotifications.forEach is not a function",
        "stack":"InternalServerError: allNotifications.forEach is not a function\n    at new GhostError (/var/www/ghost/versions/4.5.0/node_modules/@tryghost/errors/lib/errors.js:10:26)\n    at _private.prepareError (/var/www/ghost/versions/4.5.0/core/server/web/shared/middlewares/error-handler.js:53:19)\n    at Layer.handle_error (/var/www/ghost/versions/4.5.0/node_modules/express/lib/router/layer.js:71:5)\n    at trim_prefix (/var/www/ghost/versions/4.5.0/node_modules/express/lib/router/index.js:315:13)\n    at /var/www/ghost/versions/4.5.0/node_modules/express/lib/router/index.js:284:7\n    at Function.process_params (/var/www/ghost/versions/4.5.0/node_modules/express/lib/router/index.js:335:12)\n    at next (/var/www/ghost/versions/4.5.0/node_modules/express/lib/router/index.js:275:10)\n    at Layer.handle_error (/var/www/ghost/versions/4.5.0/node_modules/express/lib/router/layer.js:67:12)\n    at trim_prefix (/var/www/ghost/versions/4.5.0/node_modules/express/lib/router/index.js:315:13)\n    at /var/www/ghost/versions/4.5.0/node_modules/express/lib/router/index.js:284:7\n    at Function.process_params (/var/www/ghost/versions/4.5.0/node_modules/express/lib/router/index.js:335:12)\n    at next (/var/www/ghost/versions/4.5.0/node_modules/express/lib/router/index.js:275:10)\n    at /var/www/ghost/versions/4.5.0/node_modules/express/lib/router/index.js:635:15\n    at next (/var/www/ghost/versions/4.5.0/node_modules/express/lib/router/index.js:260:14)\n    at next (/var/www/ghost/versions/4.5.0/node_modules/express/lib/router/route.js:127:14)\n    at /var/www/ghost/versions/4.5.0/core/server/api/shared/http.js:124:17\n    at tryCatcher (/var/www/ghost/versions/4.5.0/node_modules/bluebird/js/release/util.js:16:23)\n    at Promise._settlePromiseFromHandler (/var/www/ghost/versions/4.5.0/node_modules/bluebird/js/release/promise.js:547:31)\n    at Promise._settlePromise (/var/www/ghost/versions/4.5.0/node_modules/bluebird/js/release/promise.js:604:18)\n    at Promise._settlePromise0 (/var/www/ghost/versions/4.5.0/node_modules/bluebird/js/release/promise.js:649:10)\n    at Promise._settlePromises (/var/www/ghost/versions/4.5.0/node_modules/bluebird/js/release/promise.js:725:18)\n    at _drainQueueStep (/var/www/ghost/versions/4.5.0/node_modules/bluebird/js/release/async.js:93:12)\n\nTypeError: allNotifications.forEach is not a function\n    at Notifications.fetchAllNotifications (/var/www/ghost/versions/4.5.0/core/server/services/notifications/notifications.js:26:26)\n    at Notifications.browse (/var/www/ghost/versions/4.5.0/core/server/services/notifications/notifications.js:42:37)\n    at Object.query (/var/www/ghost/versions/4.5.0/core/server/api/canary/notifications.js:11:34)\n    at Object.query (/var/www/ghost/versions/4.5.0/core/server/api/shared/pipeline.js:156:24)\n    at /var/www/ghost/versions/4.5.0/core/server/api/shared/pipeline.js:243:35\n    at tryCatcher (/var/www/ghost/versions/4.5.0/node_modules/bluebird/js/release/util.js:16:23)\n    at Promise._settlePromiseFromHandler (/var/www/ghost/versions/4.5.0/node_modules/bluebird/js/release/promise.js:547:31)\n    at Promise._settlePromise (/var/www/ghost/versions/4.5.0/node_modules/bluebird/js/release/promise.js:604:18)\n    at Promise._settlePromise0 (/var/www/ghost/versions/4.5.0/node_modules/bluebird/js/release/promise.js:649:10)\n    at Promise._settlePromises (/var/www/ghost/versions/4.5.0/node_modules/bluebird/js/release/promise.js:729:18)\n    at _drainQueueStep (/var/www/ghost/versions/4.5.0/node_modules/bluebird/js/release/async.js:93:12)\n    at _drainQueue (/var/www/ghost/versions/4.5.0/node_modules/bluebird/js/release/async.js:86:9)\n    at Async._drainQueues (/var/www/ghost/versions/4.5.0/node_modules/bluebird/js/release/async.js:102:5)\n    at Immediate.Async.drainQueues [as _onImmediate] (/var/www/ghost/versions/4.5.0/node_modules/bluebird/js/release/async.js:15:14)\n    at processImmediate (internal/timers.js:461:21)"
     },
     "msg":"allNotifications.forEach is not a function",
     "time":"2021-05-14T23:35:52.611Z",
     "v":0
  }
1 Like

I get this error repeatedly while browsing the Admin panel, and it didn’t result in something unexpected. Seems to be about notifications, like the ones that popped up to urge us to update to 4.3.3.

I yet have 0 MRR, so I cannot check, but might in a while.

1 Like

Okay, I think I figured this out. When the newsletter was with Substack, the subscription prices were in CAD, but during the move I changed them to USD, since most paid members are in the US anyway. There haven’t been any new paid subscriptions since the move, so the dashboard is displaying an MRR of US$0.

When I go to Settings > Products I see:

products

Just because I’m a neat freak, I’m tempted to archive the old CAD price points. That won’t do anything screwy to the currently-existing CAD subscribers in Stripe, will it?

Since posting the previous update I’ve upgraded to Ghost v4.6.4 and it looks like the Settings > Products page has vanished. The problem I have now is that when a user clicks the Upgrade link it takes them to a Stripe page that shows a subscription option combining CAD and USD currencies.

Screenshot 2021-05-28 at 13.13.31

I think I’d be reluctant to input my payment details for a product when it’s unclear what price is being charged. Plus, it just looks unprofessional. How do I change this to get rid of the “CA$5 a month”?

Okay. After looking at old database backups I think I’ve made some progress in figuring out what happened here. This seems to be an issue that was introduced by the 4.3 database migration.

To recap: the newsletter I’m administering began on Substack, where the price points were CAD$5/month or CAD$50/year. During the migration we decided to change our prices to USD$5 and USD$50.

Since the move we’ve had one new USD$50 subscription and no USD$5 subscriptions. All the other subscriptions are on the legacy Substack CAD pricing.

When I installed Ghost, it created a new product in my Stripe account with the correct pricing levels, as shown below. (And, as I said, we got one yearly subscription using these prices.)

Screenshot 2021-05-28 at 15.20.17

Then when we upgraded to 4.3, the new stripe_prices database table was populated from data in the customer subscriptions table. But because we didn’t have any USD$5 subscriptions yet, that process only added rows for the legacy Substack price points and the new yearly and complimentary tiers.

Screenshot 2021-05-28 at 14.54.58

Then on May 11, a row for the USD$5 tier was added to the Ghost database. (I’m not sure why. An automatic process? Maybe someone clicked the Upgrade link but didn’t complete the checkout process?) But instead of linking to the new Ghost product on Stripe, it links to the legacy CAD$5 Substack product, which got a new USD$5 price point added to it.

Screenshot 2021-05-28 at 15.27.32

Does anyone have advice on how to link Ghost to the correct Stripe product? Is it as simple as updating the stripe_prices table with the correct stripe_price_id and stripe_product_id?