diff --git a/app/controllers/invoices_controller.rb b/app/controllers/invoices_controller.rb
new file mode 100644
index 0000000..57dc385
--- /dev/null
+++ b/app/controllers/invoices_controller.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module DiscoursePatrons
+ class InvoicesController < ::ApplicationController
+ include DiscoursePatrons::Stripe
+
+ requires_login
+
+ before_action :set_api_key
+
+ def index
+ begin
+ customer = find_customer
+
+ if viewing_own_invoices && customer.present?
+ invoices = ::Stripe::Invoice.list(customer: customer.customer_id)
+
+ render_json_dump invoices.data
+ else
+ render_json_dump []
+ end
+ rescue ::Stripe::InvalidRequestError => e
+ return render_json_error e.message
+ end
+ end
+
+ private
+
+ def viewing_own_invoices
+ current_user.id == params[:user_id].to_i
+ end
+
+ def find_customer
+ DiscoursePatrons::Customer.find_user(current_user)
+ end
+ end
+end
diff --git a/assets/javascripts/discourse/models/invoice.js.es6 b/assets/javascripts/discourse/models/invoice.js.es6
new file mode 100644
index 0000000..f4a447b
--- /dev/null
+++ b/assets/javascripts/discourse/models/invoice.js.es6
@@ -0,0 +1,19 @@
+import computed from "ember-addons/ember-computed-decorators";
+import { ajax } from "discourse/lib/ajax";
+
+const Invoice = Discourse.Model.extend({
+ @computed("created")
+ createdFormatted(created) {
+ return moment.unix(created).format();
+ }
+});
+
+Invoice.reopenClass({
+ findAll() {
+ return ajax("/patrons/invoices", { method: "get" }).then(result =>
+ result.map(invoice => Invoice.create(invoice))
+ );
+ }
+});
+
+export default Invoice;
diff --git a/assets/javascripts/discourse/routes/user-billing.js.es6 b/assets/javascripts/discourse/routes/user-billing.js.es6
index 9ce293f..ad03653 100644
--- a/assets/javascripts/discourse/routes/user-billing.js.es6
+++ b/assets/javascripts/discourse/routes/user-billing.js.es6
@@ -1,6 +1,8 @@
+import Invoice from "discourse/plugins/discourse-patrons/discourse/models/invoice";
+
export default Discourse.Route.extend({
model() {
- return {};
+ return Invoice.findAll();
},
setupController(controller, model) {
diff --git a/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-dashboard.hbs b/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-dashboard.hbs
index cda4b3b..1aa2d58 100644
--- a/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-dashboard.hbs
+++ b/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-dashboard.hbs
@@ -1,9 +1,9 @@
{{i18n 'discourse_patrons.admin.dashboard.title'}}
-{{#load-more selector=".discourse-patrons-admin tr" action=(action "loadMore")}}
+{{#load-more selector=".discourse-patrons-table tr" action=(action "loadMore")}}
{{#if model}}
-
+
{{i18n 'discourse_patrons.admin.dashboard.table.head.user'}} |
diff --git a/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-plans-index.hbs b/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-plans-index.hbs
index b89639d..1b37a2e 100644
--- a/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-plans-index.hbs
+++ b/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-plans-index.hbs
@@ -1,5 +1,5 @@
-
+
{{i18n 'discourse_patrons.admin.plans.plan.plan_id'}} |
{{i18n 'discourse_patrons.admin.plans.plan.nickname.title'}} |
diff --git a/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-products-index.hbs b/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-products-index.hbs
index 69d785d..9eb8bf5 100644
--- a/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-products-index.hbs
+++ b/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-products-index.hbs
@@ -7,7 +7,7 @@
{{#if model}}
-
+
{{i18n 'discourse_patrons.admin.products.product.name'}} |
{{i18n 'discourse_patrons.admin.products.product.created_at'}} |
diff --git a/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-products-show.hbs b/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-products-show.hbs
index f596cc2..35071b6 100644
--- a/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-products-show.hbs
+++ b/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-products-show.hbs
@@ -24,7 +24,7 @@
{{i18n 'discourse_patrons.admin.plans.title'}}
-
+
{{i18n 'discourse_patrons.admin.plans.plan.nickname'}} |
{{i18n 'discourse_patrons.admin.plans.plan.interval'}} |
diff --git a/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-subscriptions.hbs b/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-subscriptions.hbs
index 383f50a..92598f1 100644
--- a/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-subscriptions.hbs
+++ b/assets/javascripts/discourse/templates/admin/plugins-discourse-patrons-subscriptions.hbs
@@ -1,5 +1,5 @@
-
+
{{i18n 'discourse_patrons.admin.subscriptions.subscription.customer'}} |
diff --git a/assets/javascripts/discourse/templates/user/billing.hbs b/assets/javascripts/discourse/templates/user/billing.hbs
index de05057..d1ea854 100644
--- a/assets/javascripts/discourse/templates/user/billing.hbs
+++ b/assets/javascripts/discourse/templates/user/billing.hbs
@@ -1,3 +1,27 @@
+{{i18n 'discourse_patrons.user.billing.title'}}
-user/billing
+{{#if model}}
+
+
+ {{i18n 'discourse_patrons.user.billing.invoices.amount'}} |
+ {{i18n 'discourse_patrons.user.billing.invoices.number'}} |
+ {{i18n 'discourse_patrons.user.billing.invoices.created_at'}} |
+ |
+
+ {{#each model as |invoice|}}
+
+ {{invoice.amount_paid}} |
+ {{invoice.number}} |
+ {{format-date invoice.createdFormatted}} |
+
+
+ {{d-icon "download"}}
+
+ |
+
+ {{/each}}
+
+{{else}}
+ {{i18n 'discourse_patrons.user.billing_help'}}
+{{/if}}
diff --git a/assets/stylesheets/common/discourse-patrons-layout.scss b/assets/stylesheets/common/discourse-patrons-layout.scss
new file mode 100644
index 0000000..0211bbd
--- /dev/null
+++ b/assets/stylesheets/common/discourse-patrons-layout.scss
@@ -0,0 +1,33 @@
+.discourse-patrons-section-columns {
+ display: flex;
+ justify-content: space-between;
+
+ @include breakpoint(medium) {
+ flex-direction: column;
+ }
+
+ .section-column {
+ min-width: calc(50% - 0.5em);
+ max-width: 100%;
+
+ &:last-child {
+ margin-left: 0.5em;
+ }
+
+ &:first-child {
+ margin-right: 0.5em;
+ }
+
+ @include breakpoint(medium) {
+ min-width: 100%;
+
+ &:last-child {
+ order: 2;
+ }
+
+ &:first-child {
+ order: 1;
+ }
+ }
+ }
+}
diff --git a/assets/stylesheets/common/discourse-patrons.scss b/assets/stylesheets/common/discourse-patrons.scss
index 219ff4d..504d76e 100644
--- a/assets/stylesheets/common/discourse-patrons.scss
+++ b/assets/stylesheets/common/discourse-patrons.scss
@@ -10,47 +10,13 @@ textarea[readonly] {
border-color: #e9e9e9;
}
-.discourse-patrons-section-columns {
- display: flex;
- justify-content: space-between;
-
- @include breakpoint(medium) {
- flex-direction: column;
- }
-
- .section-column {
- min-width: calc(50% - 0.5em);
- max-width: 100%;
-
- &:last-child {
- margin-left: 0.5em;
- }
-
- &:first-child {
- margin-right: 0.5em;
- }
-
- @include breakpoint(medium) {
- min-width: 100%;
-
- &:last-child {
- order: 2;
- }
-
- &:first-child {
- order: 1;
- }
- }
- }
-}
-
#discourse-patrons-admin {
.btn-right {
text-align: right;
}
}
-table.discourse-patrons-admin {
+table.discourse-patrons-table {
.td-right {
text-align: right;
}
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 99b4a6e..64edaaa 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -20,7 +20,15 @@ en:
navigation:
subscribe: Subscribe
billing: Billing
- subscribe:
+ user:
+ billing_help: We couldn't find a customer identifier in our system.
+ billing:
+ title: Billing
+ invoices:
+ amount: Amount
+ number: Invoice Number
+ created_at: Created
+ subscribe:
title: Subscribe
card:
title: Payment
diff --git a/config/routes.rb b/config/routes.rb
index 59692a5..5d16e81 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -13,10 +13,11 @@ DiscoursePatrons::Engine.routes.draw do
end
resources :customers, only: [:create]
- resources :subscriptions, only: [:create]
+ resources :invoices, only: [:index]
+ resources :patrons, only: [:index, :create]
resources :plans, only: [:index]
resources :products, only: [:index]
- resources :patrons, only: [:index, :create]
+ resources :subscriptions, only: [:create]
get '/' => 'patrons#index'
end
diff --git a/plugin.rb b/plugin.rb
index 7e0be0c..6b48b1d 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -11,6 +11,7 @@ enabled_site_setting :discourse_patrons_enabled
gem 'stripe', '5.7.1'
register_asset "stylesheets/common/discourse-patrons.scss"
+register_asset "stylesheets/common/discourse-patrons-layout.scss"
register_asset "stylesheets/mobile/discourse-patrons.scss"
register_svg_icon "credit-card" if respond_to?(:register_svg_icon)
@@ -50,6 +51,7 @@ after_initialize do
"../app/controllers/admin/products_controller",
"../app/controllers/admin/subscriptions_controller",
"../app/controllers/customers_controller",
+ "../app/controllers/invoices_controller",
"../app/controllers/patrons_controller",
"../app/controllers/plans_controller",
"../app/controllers/products_controller",
diff --git a/spec/requests/invoices_controller_spec.rb b/spec/requests/invoices_controller_spec.rb
new file mode 100644
index 0000000..1620075
--- /dev/null
+++ b/spec/requests/invoices_controller_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+module DiscoursePatrons
+ RSpec.describe InvoicesController do
+ describe "index" do
+ describe "not authenticated" do
+ it "does not list the invoices" do
+ ::Stripe::Invoice.expects(:list).never
+ get "/patrons/invoices.json"
+ expect(response.status).to eq 403
+ end
+ end
+
+ describe "authenticated" do
+ let(:user) { Fabricate(:user) }
+ let(:stripe_customer) { { id: 'cus_id4567' } }
+
+ before do
+ sign_in(user)
+ end
+
+ describe "other user invoices" do
+ it "does not list the invoices" do
+ ::Stripe::Invoice.expects(:list).never
+ get "/patrons/invoices.json", params: { user_id: 999999 }
+ end
+ end
+
+ describe "own invoices" do
+ context "stripe customer does not exist" do
+ it "lists empty" do
+ ::Stripe::Invoice.expects(:list).never
+ get "/patrons/invoices.json", params: { user_id: user.id }
+ expect(response.body).to eq "[]"
+ end
+ end
+
+ context "stripe customer exists" do
+ before do
+ DiscoursePatrons::Customer.create_customer(user, stripe_customer)
+ end
+
+ it "lists the invoices" do
+ ::Stripe::Invoice.expects(:list).with(customer: 'cus_id4567')
+ get "/patrons/invoices.json", params: { user_id: user.id }
+ end
+ end
+ end
+ end
+ end
+ end
+end