From 1301011b4fc77b8d5edf9d728caae4c8571df5a0 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 12 Apr 2022 15:51:39 +0200 Subject: [PATCH 1/2] Document VatCalculator v3 changes --- .vuepress/dist/1.x/index.html | 6 +++--- .vuepress/dist/1.x/installation.html | 6 +++--- .vuepress/dist/1.x/introduction.html | 6 +++--- .../dist/1.x/spark-paddle/configuration.html | 6 +++--- .vuepress/dist/1.x/spark-paddle/cookbook.html | 6 +++--- .../dist/1.x/spark-paddle/customization.html | 6 +++--- .vuepress/dist/1.x/spark-paddle/events.html | 6 +++--- .vuepress/dist/1.x/spark-paddle/index.html | 6 +++--- .vuepress/dist/1.x/spark-paddle/middleware.html | 6 +++--- .vuepress/dist/1.x/spark-paddle/plans.html | 6 +++--- .vuepress/dist/1.x/spark-paddle/testing.html | 6 +++--- .../dist/1.x/spark-stripe/configuration.html | 6 +++--- .vuepress/dist/1.x/spark-stripe/cookbook.html | 6 +++--- .../dist/1.x/spark-stripe/customization.html | 6 +++--- .vuepress/dist/1.x/spark-stripe/events.html | 6 +++--- .vuepress/dist/1.x/spark-stripe/index.html | 6 +++--- .vuepress/dist/1.x/spark-stripe/middleware.html | 6 +++--- .vuepress/dist/1.x/spark-stripe/plans.html | 6 +++--- .vuepress/dist/1.x/spark-stripe/taxes.html | 6 +++--- .vuepress/dist/1.x/spark-stripe/testing.html | 6 +++--- .vuepress/dist/1.x/upgrade.html | 6 +++--- .vuepress/dist/2.x/index.html | 6 +++--- .vuepress/dist/2.x/installation.html | 6 +++--- .vuepress/dist/2.x/introduction.html | 6 +++--- .../dist/2.x/spark-paddle/configuration.html | 6 +++--- .vuepress/dist/2.x/spark-paddle/cookbook.html | 6 +++--- .../dist/2.x/spark-paddle/customization.html | 6 +++--- .vuepress/dist/2.x/spark-paddle/events.html | 6 +++--- .vuepress/dist/2.x/spark-paddle/index.html | 6 +++--- .vuepress/dist/2.x/spark-paddle/middleware.html | 6 +++--- .vuepress/dist/2.x/spark-paddle/plans.html | 6 +++--- .vuepress/dist/2.x/spark-paddle/testing.html | 6 +++--- .vuepress/dist/2.x/spark-paddle/upgrade.html | 13 +++++++++---- .../dist/2.x/spark-stripe/configuration.html | 6 +++--- .vuepress/dist/2.x/spark-stripe/cookbook.html | 6 +++--- .../dist/2.x/spark-stripe/customization.html | 6 +++--- .vuepress/dist/2.x/spark-stripe/events.html | 6 +++--- .vuepress/dist/2.x/spark-stripe/index.html | 6 +++--- .vuepress/dist/2.x/spark-stripe/middleware.html | 6 +++--- .vuepress/dist/2.x/spark-stripe/plans.html | 6 +++--- .vuepress/dist/2.x/spark-stripe/taxes.html | 6 +++--- .vuepress/dist/2.x/spark-stripe/testing.html | 6 +++--- .vuepress/dist/2.x/spark-stripe/upgrade.html | 16 ++++++++-------- .vuepress/dist/404.html | 8 ++++---- ...styles.06302184.css => 0.styles.c0c886bb.css} | 2 +- .../assets/js/{11.6b26706e.js => 11.3605d95f.js} | 2 +- .../assets/js/{12.f432fe5b.js => 12.965072a7.js} | 2 +- .../assets/js/{32.413bc4f0.js => 13.ca148558.js} | 2 +- .../assets/js/{14.94f4369e.js => 14.382f113d.js} | 2 +- .../assets/js/{15.65efddc6.js => 15.be446089.js} | 2 +- .../assets/js/{16.edc3dc4f.js => 16.10ef0c2b.js} | 2 +- .../assets/js/{36.a14c3334.js => 17.f62f4989.js} | 2 +- .../assets/js/{18.92e12c06.js => 18.be1ab332.js} | 2 +- .../assets/js/{19.270a8496.js => 19.bdc35da2.js} | 2 +- .../assets/js/{39.cf57a51d.js => 20.ae0c3f38.js} | 2 +- .../assets/js/{21.bce379e0.js => 21.fad78231.js} | 2 +- .../assets/js/{42.002a01e2.js => 22.3214753d.js} | 2 +- .../assets/js/{43.1e21ec9e.js => 23.c2854556.js} | 2 +- .../assets/js/{24.7ec9d664.js => 24.9d499e01.js} | 2 +- .../assets/js/{25.9ef58848.js => 25.541847d5.js} | 2 +- .../assets/js/{46.d43a6bb8.js => 26.cd5b169e.js} | 2 +- .../assets/js/{27.8166b3a7.js => 27.47550fce.js} | 2 +- .../assets/js/{28.d97c5e89.js => 28.e31447b8.js} | 2 +- .../assets/js/{29.1cb997ca.js => 29.54c4da39.js} | 2 +- .../assets/js/{50.a45b7f9f.js => 30.8819ef2d.js} | 2 +- .../assets/js/{31.10d0fc8c.js => 31.c977b44e.js} | 2 +- .../assets/js/{13.28105fba.js => 32.86d65ba4.js} | 2 +- .../assets/js/{33.e8c3aa03.js => 33.07907b79.js} | 2 +- .../assets/js/{34.10bc56b7.js => 34.faa735ab.js} | 2 +- .../assets/js/{17.b8ed5059.js => 36.b4f36b7c.js} | 2 +- .../assets/js/{38.8ca8435c.js => 38.72d71636.js} | 2 +- .../assets/js/{20.60dbd01c.js => 39.5695320f.js} | 2 +- .../assets/js/{4.575bc5ce.js => 4.5f6bfe57.js} | 2 +- .vuepress/dist/assets/js/40.118df548.js | 1 - .vuepress/dist/assets/js/40.a764658c.js | 1 + .../assets/js/{41.f6cd3bbc.js => 41.803aa421.js} | 2 +- .../assets/js/{22.db9640d4.js => 42.c55c2039.js} | 2 +- .../assets/js/{23.5c58e10a.js => 43.63f50d56.js} | 2 +- .../assets/js/{44.f9b6e351.js => 44.ee3a873b.js} | 2 +- .../assets/js/{45.96b85397.js => 45.1ad8fcd1.js} | 2 +- .../assets/js/{26.dbfdd111.js => 46.4c3e9d67.js} | 2 +- .../assets/js/{48.38168e03.js => 48.5e3bfa48.js} | 2 +- .vuepress/dist/assets/js/49.52b310b3.js | 1 + .vuepress/dist/assets/js/49.72f352fe.js | 1 - .../assets/js/{5.5d3848bb.js => 5.9e9fc063.js} | 2 +- .../assets/js/{30.d6a51d12.js => 50.4891d2a2.js} | 2 +- .../assets/js/{51.ca79f3f4.js => 51.16efd940.js} | 2 +- .../assets/js/{6.6e39d20d.js => 6.78edb7c1.js} | 2 +- .../assets/js/{7.ba3c63d4.js => 7.f0182c65.js} | 2 +- .../assets/js/{8.9c7fdb39.js => 8.c63c2f3a.js} | 2 +- .../assets/js/{9.36f96429.js => 9.9b279207.js} | 2 +- .../js/{app.f3c199dd.js => app.95651ca8.js} | 4 ++-- .vuepress/dist/examples.html | 6 +++--- .vuepress/dist/index.html | 6 +++--- 2.x/spark-stripe/upgrade.md | 5 +++++ 95 files changed, 202 insertions(+), 192 deletions(-) rename .vuepress/dist/assets/css/{0.styles.06302184.css => 0.styles.c0c886bb.css} (97%) rename .vuepress/dist/assets/js/{11.6b26706e.js => 11.3605d95f.js} (83%) rename .vuepress/dist/assets/js/{12.f432fe5b.js => 12.965072a7.js} (99%) rename .vuepress/dist/assets/js/{32.413bc4f0.js => 13.ca148558.js} (99%) rename .vuepress/dist/assets/js/{14.94f4369e.js => 14.382f113d.js} (84%) rename .vuepress/dist/assets/js/{15.65efddc6.js => 15.be446089.js} (99%) rename .vuepress/dist/assets/js/{16.edc3dc4f.js => 16.10ef0c2b.js} (99%) rename .vuepress/dist/assets/js/{36.a14c3334.js => 17.f62f4989.js} (99%) rename .vuepress/dist/assets/js/{18.92e12c06.js => 18.be1ab332.js} (98%) rename .vuepress/dist/assets/js/{19.270a8496.js => 19.bdc35da2.js} (99%) rename .vuepress/dist/assets/js/{39.cf57a51d.js => 20.ae0c3f38.js} (99%) rename .vuepress/dist/assets/js/{21.bce379e0.js => 21.fad78231.js} (84%) rename .vuepress/dist/assets/js/{42.002a01e2.js => 22.3214753d.js} (99%) rename .vuepress/dist/assets/js/{43.1e21ec9e.js => 23.c2854556.js} (99%) rename .vuepress/dist/assets/js/{24.7ec9d664.js => 24.9d499e01.js} (99%) rename .vuepress/dist/assets/js/{25.9ef58848.js => 25.541847d5.js} (98%) rename .vuepress/dist/assets/js/{46.d43a6bb8.js => 26.cd5b169e.js} (98%) rename .vuepress/dist/assets/js/{27.8166b3a7.js => 27.47550fce.js} (97%) rename .vuepress/dist/assets/js/{28.d97c5e89.js => 28.e31447b8.js} (99%) rename .vuepress/dist/assets/js/{29.1cb997ca.js => 29.54c4da39.js} (99%) rename .vuepress/dist/assets/js/{50.a45b7f9f.js => 30.8819ef2d.js} (83%) rename .vuepress/dist/assets/js/{31.10d0fc8c.js => 31.c977b44e.js} (99%) rename .vuepress/dist/assets/js/{13.28105fba.js => 32.86d65ba4.js} (99%) rename .vuepress/dist/assets/js/{33.e8c3aa03.js => 33.07907b79.js} (84%) rename .vuepress/dist/assets/js/{34.10bc56b7.js => 34.faa735ab.js} (99%) rename .vuepress/dist/assets/js/{17.b8ed5059.js => 36.b4f36b7c.js} (99%) rename .vuepress/dist/assets/js/{38.8ca8435c.js => 38.72d71636.js} (99%) rename .vuepress/dist/assets/js/{20.60dbd01c.js => 39.5695320f.js} (99%) rename .vuepress/dist/assets/js/{4.575bc5ce.js => 4.5f6bfe57.js} (67%) delete mode 100644 .vuepress/dist/assets/js/40.118df548.js create mode 100644 .vuepress/dist/assets/js/40.a764658c.js rename .vuepress/dist/assets/js/{41.f6cd3bbc.js => 41.803aa421.js} (84%) rename .vuepress/dist/assets/js/{22.db9640d4.js => 42.c55c2039.js} (99%) rename .vuepress/dist/assets/js/{23.5c58e10a.js => 43.63f50d56.js} (99%) rename .vuepress/dist/assets/js/{44.f9b6e351.js => 44.ee3a873b.js} (99%) rename .vuepress/dist/assets/js/{45.96b85397.js => 45.1ad8fcd1.js} (98%) rename .vuepress/dist/assets/js/{26.dbfdd111.js => 46.4c3e9d67.js} (98%) rename .vuepress/dist/assets/js/{48.38168e03.js => 48.5e3bfa48.js} (99%) create mode 100644 .vuepress/dist/assets/js/49.52b310b3.js delete mode 100644 .vuepress/dist/assets/js/49.72f352fe.js rename .vuepress/dist/assets/js/{5.5d3848bb.js => 5.9e9fc063.js} (89%) rename .vuepress/dist/assets/js/{30.d6a51d12.js => 50.4891d2a2.js} (83%) rename .vuepress/dist/assets/js/{51.ca79f3f4.js => 51.16efd940.js} (99%) rename .vuepress/dist/assets/js/{6.6e39d20d.js => 6.78edb7c1.js} (99%) rename .vuepress/dist/assets/js/{7.ba3c63d4.js => 7.f0182c65.js} (99%) rename .vuepress/dist/assets/js/{8.9c7fdb39.js => 8.c63c2f3a.js} (99%) rename .vuepress/dist/assets/js/{9.36f96429.js => 9.9b279207.js} (99%) rename .vuepress/dist/assets/js/{app.f3c199dd.js => app.95651ca8.js} (82%) diff --git a/.vuepress/dist/1.x/index.html b/.vuepress/dist/1.x/index.html index 845910d..a62491b 100644 --- a/.vuepress/dist/1.x/index.html +++ b/.vuepress/dist/1.x/index.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/installation.html b/.vuepress/dist/1.x/installation.html index e1ed586..d361724 100644 --- a/.vuepress/dist/1.x/installation.html +++ b/.vuepress/dist/1.x/installation.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/introduction.html b/.vuepress/dist/1.x/introduction.html index 0d50459..a7f0359 100644 --- a/.vuepress/dist/1.x/introduction.html +++ b/.vuepress/dist/1.x/introduction.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/spark-paddle/configuration.html b/.vuepress/dist/1.x/spark-paddle/configuration.html index fbb314c..749e0eb 100644 --- a/.vuepress/dist/1.x/spark-paddle/configuration.html +++ b/.vuepress/dist/1.x/spark-paddle/configuration.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/spark-paddle/cookbook.html b/.vuepress/dist/1.x/spark-paddle/cookbook.html index b15e52b..0df43d4 100644 --- a/.vuepress/dist/1.x/spark-paddle/cookbook.html +++ b/.vuepress/dist/1.x/spark-paddle/cookbook.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/spark-paddle/customization.html b/.vuepress/dist/1.x/spark-paddle/customization.html index 1c18cbb..e77e816 100644 --- a/.vuepress/dist/1.x/spark-paddle/customization.html +++ b/.vuepress/dist/1.x/spark-paddle/customization.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/spark-paddle/events.html b/.vuepress/dist/1.x/spark-paddle/events.html index 6603ca3..5fd670c 100644 --- a/.vuepress/dist/1.x/spark-paddle/events.html +++ b/.vuepress/dist/1.x/spark-paddle/events.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/spark-paddle/index.html b/.vuepress/dist/1.x/spark-paddle/index.html index f09465f..ab4a367 100644 --- a/.vuepress/dist/1.x/spark-paddle/index.html +++ b/.vuepress/dist/1.x/spark-paddle/index.html @@ -14,8 +14,8 @@ - - + + - + diff --git a/.vuepress/dist/1.x/spark-paddle/middleware.html b/.vuepress/dist/1.x/spark-paddle/middleware.html index 5efd614..8df7e77 100644 --- a/.vuepress/dist/1.x/spark-paddle/middleware.html +++ b/.vuepress/dist/1.x/spark-paddle/middleware.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/spark-paddle/plans.html b/.vuepress/dist/1.x/spark-paddle/plans.html index d4f17db..29f3b93 100644 --- a/.vuepress/dist/1.x/spark-paddle/plans.html +++ b/.vuepress/dist/1.x/spark-paddle/plans.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/spark-paddle/testing.html b/.vuepress/dist/1.x/spark-paddle/testing.html index ce3aa52..9b58b99 100644 --- a/.vuepress/dist/1.x/spark-paddle/testing.html +++ b/.vuepress/dist/1.x/spark-paddle/testing.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/spark-stripe/configuration.html b/.vuepress/dist/1.x/spark-stripe/configuration.html index cf84ebd..b20f40c 100644 --- a/.vuepress/dist/1.x/spark-stripe/configuration.html +++ b/.vuepress/dist/1.x/spark-stripe/configuration.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/spark-stripe/cookbook.html b/.vuepress/dist/1.x/spark-stripe/cookbook.html index 0699b51..9fe1d0d 100644 --- a/.vuepress/dist/1.x/spark-stripe/cookbook.html +++ b/.vuepress/dist/1.x/spark-stripe/cookbook.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/spark-stripe/customization.html b/.vuepress/dist/1.x/spark-stripe/customization.html index 192bcf7..a982bc7 100644 --- a/.vuepress/dist/1.x/spark-stripe/customization.html +++ b/.vuepress/dist/1.x/spark-stripe/customization.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/spark-stripe/events.html b/.vuepress/dist/1.x/spark-stripe/events.html index f25fd6c..59d5db9 100644 --- a/.vuepress/dist/1.x/spark-stripe/events.html +++ b/.vuepress/dist/1.x/spark-stripe/events.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/spark-stripe/index.html b/.vuepress/dist/1.x/spark-stripe/index.html index 68954dc..ad6ecee 100644 --- a/.vuepress/dist/1.x/spark-stripe/index.html +++ b/.vuepress/dist/1.x/spark-stripe/index.html @@ -14,8 +14,8 @@ - - + + - + diff --git a/.vuepress/dist/1.x/spark-stripe/middleware.html b/.vuepress/dist/1.x/spark-stripe/middleware.html index 6ed05d1..930f1ed 100644 --- a/.vuepress/dist/1.x/spark-stripe/middleware.html +++ b/.vuepress/dist/1.x/spark-stripe/middleware.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/spark-stripe/plans.html b/.vuepress/dist/1.x/spark-stripe/plans.html index cfff68f..81baec2 100644 --- a/.vuepress/dist/1.x/spark-stripe/plans.html +++ b/.vuepress/dist/1.x/spark-stripe/plans.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/spark-stripe/taxes.html b/.vuepress/dist/1.x/spark-stripe/taxes.html index 3cdc2dd..2ba54b9 100644 --- a/.vuepress/dist/1.x/spark-stripe/taxes.html +++ b/.vuepress/dist/1.x/spark-stripe/taxes.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/spark-stripe/testing.html b/.vuepress/dist/1.x/spark-stripe/testing.html index 8d405ce..9d25333 100644 --- a/.vuepress/dist/1.x/spark-stripe/testing.html +++ b/.vuepress/dist/1.x/spark-stripe/testing.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/1.x/upgrade.html b/.vuepress/dist/1.x/upgrade.html index 15deaf0..66f0368 100644 --- a/.vuepress/dist/1.x/upgrade.html +++ b/.vuepress/dist/1.x/upgrade.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/index.html b/.vuepress/dist/2.x/index.html index e9582ce..2c0e7c4 100644 --- a/.vuepress/dist/2.x/index.html +++ b/.vuepress/dist/2.x/index.html @@ -14,8 +14,8 @@ - - + + - + diff --git a/.vuepress/dist/2.x/installation.html b/.vuepress/dist/2.x/installation.html index 2970ee8..66a21d4 100644 --- a/.vuepress/dist/2.x/installation.html +++ b/.vuepress/dist/2.x/installation.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/introduction.html b/.vuepress/dist/2.x/introduction.html index 639001d..f615ffd 100644 --- a/.vuepress/dist/2.x/introduction.html +++ b/.vuepress/dist/2.x/introduction.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-paddle/configuration.html b/.vuepress/dist/2.x/spark-paddle/configuration.html index 7f8a9cc..97943ad 100644 --- a/.vuepress/dist/2.x/spark-paddle/configuration.html +++ b/.vuepress/dist/2.x/spark-paddle/configuration.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-paddle/cookbook.html b/.vuepress/dist/2.x/spark-paddle/cookbook.html index 5f53cd0..bd2fd24 100644 --- a/.vuepress/dist/2.x/spark-paddle/cookbook.html +++ b/.vuepress/dist/2.x/spark-paddle/cookbook.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-paddle/customization.html b/.vuepress/dist/2.x/spark-paddle/customization.html index bffc642..40325d6 100644 --- a/.vuepress/dist/2.x/spark-paddle/customization.html +++ b/.vuepress/dist/2.x/spark-paddle/customization.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-paddle/events.html b/.vuepress/dist/2.x/spark-paddle/events.html index 463a05c..f178c63 100644 --- a/.vuepress/dist/2.x/spark-paddle/events.html +++ b/.vuepress/dist/2.x/spark-paddle/events.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-paddle/index.html b/.vuepress/dist/2.x/spark-paddle/index.html index aef1bd2..ec898a4 100644 --- a/.vuepress/dist/2.x/spark-paddle/index.html +++ b/.vuepress/dist/2.x/spark-paddle/index.html @@ -14,8 +14,8 @@ - - + + - + diff --git a/.vuepress/dist/2.x/spark-paddle/middleware.html b/.vuepress/dist/2.x/spark-paddle/middleware.html index 684a9f2..b3187a5 100644 --- a/.vuepress/dist/2.x/spark-paddle/middleware.html +++ b/.vuepress/dist/2.x/spark-paddle/middleware.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-paddle/plans.html b/.vuepress/dist/2.x/spark-paddle/plans.html index cbb3fea..d2e04ec 100644 --- a/.vuepress/dist/2.x/spark-paddle/plans.html +++ b/.vuepress/dist/2.x/spark-paddle/plans.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-paddle/testing.html b/.vuepress/dist/2.x/spark-paddle/testing.html index 806f5d8..57ea7a3 100644 --- a/.vuepress/dist/2.x/spark-paddle/testing.html +++ b/.vuepress/dist/2.x/spark-paddle/testing.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-paddle/upgrade.html b/.vuepress/dist/2.x/spark-paddle/upgrade.html index d7e41e2..8ea6fcb 100644 --- a/.vuepress/dist/2.x/spark-paddle/upgrade.html +++ b/.vuepress/dist/2.x/spark-paddle/upgrade.html @@ -14,8 +14,8 @@ - - + +

# Upgrade

# Upgrading to Spark (Paddle) 2.0 From v1.x

Spark (Paddle) 2.0 is a maintenance release with no breaking changes. To upgrade, simply update your application's composer.json file to depend on the latest release:

"require": {
+    "php": "^8.0",
+    "laravel/framework": "^9.0",
+    "laravel/spark-paddle": "^2.0"
+},
+

# Minimum Versions

The following required dependency versions have been updated:

  • The minimum Laravel version is now v9.0
  • The minimum PHP version is now v8.0
- + diff --git a/.vuepress/dist/2.x/spark-stripe/configuration.html b/.vuepress/dist/2.x/spark-stripe/configuration.html index 3a719bc..4fea082 100644 --- a/.vuepress/dist/2.x/spark-stripe/configuration.html +++ b/.vuepress/dist/2.x/spark-stripe/configuration.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-stripe/cookbook.html b/.vuepress/dist/2.x/spark-stripe/cookbook.html index 61a84d0..69a2cb8 100644 --- a/.vuepress/dist/2.x/spark-stripe/cookbook.html +++ b/.vuepress/dist/2.x/spark-stripe/cookbook.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-stripe/customization.html b/.vuepress/dist/2.x/spark-stripe/customization.html index 6731904..5573191 100644 --- a/.vuepress/dist/2.x/spark-stripe/customization.html +++ b/.vuepress/dist/2.x/spark-stripe/customization.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-stripe/events.html b/.vuepress/dist/2.x/spark-stripe/events.html index de3a592..687c2af 100644 --- a/.vuepress/dist/2.x/spark-stripe/events.html +++ b/.vuepress/dist/2.x/spark-stripe/events.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-stripe/index.html b/.vuepress/dist/2.x/spark-stripe/index.html index 54afd8f..e27dc9f 100644 --- a/.vuepress/dist/2.x/spark-stripe/index.html +++ b/.vuepress/dist/2.x/spark-stripe/index.html @@ -14,8 +14,8 @@ - - + + - + diff --git a/.vuepress/dist/2.x/spark-stripe/middleware.html b/.vuepress/dist/2.x/spark-stripe/middleware.html index b05b2ca..497b02a 100644 --- a/.vuepress/dist/2.x/spark-stripe/middleware.html +++ b/.vuepress/dist/2.x/spark-stripe/middleware.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-stripe/plans.html b/.vuepress/dist/2.x/spark-stripe/plans.html index 76f8603..17b2bf6 100644 --- a/.vuepress/dist/2.x/spark-stripe/plans.html +++ b/.vuepress/dist/2.x/spark-stripe/plans.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-stripe/taxes.html b/.vuepress/dist/2.x/spark-stripe/taxes.html index 2085d3c..74f2a45 100644 --- a/.vuepress/dist/2.x/spark-stripe/taxes.html +++ b/.vuepress/dist/2.x/spark-stripe/taxes.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-stripe/testing.html b/.vuepress/dist/2.x/spark-stripe/testing.html index 2c2cc95..9c1a4a1 100644 --- a/.vuepress/dist/2.x/spark-stripe/testing.html +++ b/.vuepress/dist/2.x/spark-stripe/testing.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/2.x/spark-stripe/upgrade.html b/.vuepress/dist/2.x/spark-stripe/upgrade.html index fc1decc..c28cdc1 100644 --- a/.vuepress/dist/2.x/spark-stripe/upgrade.html +++ b/.vuepress/dist/2.x/spark-stripe/upgrade.html @@ -14,8 +14,8 @@ - - + +
- + diff --git a/.vuepress/dist/404.html b/.vuepress/dist/404.html index 11affc8..c9da8d7 100644 --- a/.vuepress/dist/404.html +++ b/.vuepress/dist/404.html @@ -13,13 +13,13 @@ - - + + -

404

There's nothing here.
+ - + diff --git a/.vuepress/dist/assets/css/0.styles.06302184.css b/.vuepress/dist/assets/css/0.styles.c0c886bb.css similarity index 97% rename from .vuepress/dist/assets/css/0.styles.06302184.css rename to .vuepress/dist/assets/css/0.styles.c0c886bb.css index 78585c8..1bcef2d 100644 --- a/.vuepress/dist/assets/css/0.styles.06302184.css +++ b/.vuepress/dist/assets/css/0.styles.c0c886bb.css @@ -1 +1 @@ -code[class*=language-],pre[class*=language-]{color:#ccc;background:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}.theme-default-content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:rgba(27,31,35,.05);border-radius:3px}.theme-default-content code .token.deleted{color:#ec5975}.theme-default-content code .token.inserted{color:#4099de}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}.theme-default-content pre[class*=language-] code,.theme-default-content pre code{color:#fff;padding:0;background-color:transparent;border-radius:0}div[class*=language-]{position:relative;background-color:#282c34;border-radius:6px}div[class*=language-] .highlight-lines{-webkit-user-select:none;user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.4}div[class*=language-] .highlight-lines .highlighted{background-color:rgba(0,0,0,.66)}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{background:transparent;position:relative;z-index:1}div[class*=language-]:before{position:absolute;z-index:3;top:.8em;right:1em;font-size:.75rem;color:hsla(0,0%,100%,.4)}div[class*=language-]:not(.line-numbers-mode) .line-numbers-wrapper{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlighted{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{content:" ";position:absolute;z-index:3;left:0;top:0;display:block;width:3.5rem;height:100%;background-color:rgba(0,0,0,.66)}div[class*=language-].line-numbers-mode pre{padding-left:4.5rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers-wrapper{position:absolute;top:0;width:3.5rem;text-align:center;color:hsla(0,0%,100%,.3);padding:1.25rem 0;line-height:1.4}div[class*=language-].line-numbers-mode .line-numbers-wrapper br{-webkit-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number{position:relative;z-index:4;-webkit-user-select:none;user-select:none;font-size:.85em}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;z-index:2;top:0;left:0;width:3.5rem;height:100%;border-radius:6px 0 0 6px;border-right:1px solid rgba(0,0,0,.66);background-color:#282c34}div[class~=language-js]:before{content:"js"}div[class~=language-ts]:before{content:"ts"}div[class~=language-html]:before{content:"html"}div[class~=language-md]:before{content:"md"}div[class~=language-vue]:before{content:"vue"}div[class~=language-css]:before{content:"css"}div[class~=language-sass]:before{content:"sass"}div[class~=language-scss]:before{content:"scss"}div[class~=language-less]:before{content:"less"}div[class~=language-stylus]:before{content:"stylus"}div[class~=language-go]:before{content:"go"}div[class~=language-java]:before{content:"java"}div[class~=language-c]:before{content:"c"}div[class~=language-sh]:before{content:"sh"}div[class~=language-yaml]:before{content:"yaml"}div[class~=language-py]:before{content:"py"}div[class~=language-docker]:before{content:"docker"}div[class~=language-dockerfile]:before{content:"dockerfile"}div[class~=language-makefile]:before{content:"makefile"}div[class~=language-javascript]:before{content:"js"}div[class~=language-typescript]:before{content:"ts"}div[class~=language-markup]:before{content:"html"}div[class~=language-markdown]:before{content:"md"}div[class~=language-json]:before{content:"json"}div[class~=language-ruby]:before{content:"rb"}div[class~=language-python]:before{content:"py"}div[class~=language-bash]:before{content:"sh"}.custom-block .custom-block-title{font-weight:600;margin-bottom:-.4rem}.custom-block.danger,.custom-block.tip,.custom-block.warning{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-block.tip{background-color:#f3f5f7;border-color:#42b983}.custom-block.warning{background-color:rgba(255,229,100,.3);border-color:#e7c000;color:#6b5900}.custom-block.warning .custom-block-title{color:#b29400}.custom-block.warning a{color:#2c3e50}.custom-block.danger{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.custom-block.danger .custom-block-title{color:#900}.custom-block.danger a{color:#2c3e50}.custom-block.details{display:block;position:relative;border-radius:2px;margin:1.6em 0;padding:1.6em;background-color:#eee}.custom-block.details h4{margin-top:0}.custom-block.details figure:last-child,.custom-block.details p:last-child{margin-bottom:0;padding-bottom:0}.custom-block.details summary{outline:none;cursor:pointer}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-bottom:6px solid #ccc}.arrow.down,.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent}.arrow.down{border-top:6px solid #ccc}.arrow.right{border-left:6px solid #ccc}.arrow.left,.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent}.arrow.left{border-right:6px solid #ccc}.theme-default-content:not(.custom){max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.theme-default-content:not(.custom){padding:2rem}}@media (max-width:419px){.theme-default-content:not(.custom){padding:1.5rem}}.table-of-contents .badge{vertical-align:middle}body,html{padding:0;margin:0;background-color:#fff}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:16px;color:#2c3e50}.page{padding-left:20rem}.navbar{z-index:20;right:0;height:3.6rem;background-color:#fff;box-sizing:border-box;border-bottom:1px solid #ddd}.navbar,.sidebar-mask{position:fixed;top:0;left:0}.sidebar-mask{z-index:9;width:100vw;height:100vh;display:none}.sidebar{font-size:16px;background-color:#fff;width:20rem;position:fixed;z-index:10;margin:0;top:3.6rem;left:0;bottom:0;box-sizing:border-box;border-right:1px solid #ddd;overflow-y:auto}.theme-default-content:not(.custom)>:first-child{margin-top:3.6rem}.theme-default-content:not(.custom) a:hover{text-decoration:underline}.theme-default-content:not(.custom) p.demo{padding:1rem 1.5rem;border:1px solid #ddd;border-radius:4px}.theme-default-content:not(.custom) img{max-width:100%}.theme-default-content.custom{padding:0;margin:0}.theme-default-content.custom img{max-width:100%}a{font-weight:500;text-decoration:none}a,p a code{color:#4099de}p a code{font-weight:400}kbd{background:#eee;border:.15rem solid #ddd;border-bottom:.25rem solid #ddd;border-radius:.15rem;padding:0 .15em}blockquote{font-size:1rem;color:#999;border-left:.2rem solid #dfe2e5;margin:1rem 0;padding:.25rem 0 .25rem 1rem}blockquote>p{margin:0}ol,ul{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25}.theme-default-content:not(.custom)>h1,.theme-default-content:not(.custom)>h2,.theme-default-content:not(.custom)>h3,.theme-default-content:not(.custom)>h4,.theme-default-content:not(.custom)>h5,.theme-default-content:not(.custom)>h6{margin-top:-3.1rem;padding-top:4.6rem;margin-bottom:0}.theme-default-content:not(.custom)>h1:first-child,.theme-default-content:not(.custom)>h2:first-child,.theme-default-content:not(.custom)>h3:first-child,.theme-default-content:not(.custom)>h4:first-child,.theme-default-content:not(.custom)>h5:first-child,.theme-default-content:not(.custom)>h6:first-child{margin-top:-1.5rem;margin-bottom:1rem}.theme-default-content:not(.custom)>h1:first-child+.custom-block,.theme-default-content:not(.custom)>h1:first-child+p,.theme-default-content:not(.custom)>h1:first-child+pre,.theme-default-content:not(.custom)>h2:first-child+.custom-block,.theme-default-content:not(.custom)>h2:first-child+p,.theme-default-content:not(.custom)>h2:first-child+pre,.theme-default-content:not(.custom)>h3:first-child+.custom-block,.theme-default-content:not(.custom)>h3:first-child+p,.theme-default-content:not(.custom)>h3:first-child+pre,.theme-default-content:not(.custom)>h4:first-child+.custom-block,.theme-default-content:not(.custom)>h4:first-child+p,.theme-default-content:not(.custom)>h4:first-child+pre,.theme-default-content:not(.custom)>h5:first-child+.custom-block,.theme-default-content:not(.custom)>h5:first-child+p,.theme-default-content:not(.custom)>h5:first-child+pre,.theme-default-content:not(.custom)>h6:first-child+.custom-block,.theme-default-content:not(.custom)>h6:first-child+p,.theme-default-content:not(.custom)>h6:first-child+pre{margin-top:2rem}h1:focus .header-anchor,h1:hover .header-anchor,h2:focus .header-anchor,h2:hover .header-anchor,h3:focus .header-anchor,h3:hover .header-anchor,h4:focus .header-anchor,h4:hover .header-anchor,h5:focus .header-anchor,h5:hover .header-anchor,h6:focus .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2.2rem}h2{font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #ddd}h3{font-size:1.35rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0}a.header-anchor:focus,a.header-anchor:hover{text-decoration:none}.line-number,code,kbd{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}ol,p,ul{line-height:1.7}hr{border:0;border-top:1px solid #ddd}table{border-collapse:collapse;margin:1rem 0;display:block;overflow-x:auto}tr{border-top:1px solid #dfe2e5}tr:nth-child(2n){background-color:#f6f8fa}td,th{border:1px solid #dfe2e5;padding:.6em 1em}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.no-navbar .theme-default-content:not(.custom)>h1,.theme-container.no-navbar h2,.theme-container.no-navbar h3,.theme-container.no-navbar h4,.theme-container.no-navbar h5,.theme-container.no-navbar h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .sidebar{top:0}@media (min-width:720px){.theme-container.no-sidebar .sidebar{display:none}.theme-container.no-sidebar .page{padding-left:0}}@media (max-width:959px){.sidebar{font-size:15px;width:16.4rem}.page{padding-left:16.4rem}}@media (max-width:719px){.sidebar{top:0;padding-top:3.6rem;transform:translateX(-100%);transition:transform .2s ease}.page{padding-left:0}.theme-container.sidebar-open .sidebar{transform:translateX(0)}.theme-container.no-navbar .sidebar{padding-top:0}}@media (max-width:419px){h1{font-size:1.9rem}.theme-default-content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}body{background-color:#eef1f4;font-family:Nunito}h1,h2,h3,h4,h5,h6{font-weight:300}h1{padding-bottom:16px;border-bottom:2px solid rgba(0,0,0,.05)}h2{border-bottom:0}@media (min-width:720px){.page{padding-left:13.75rem}.page-nav{padding:0}.page-nav>.inner{padding:0;border-top:none}}.navbar{z-index:500;border-bottom:none;box-shadow:0 2px 4px 0 rgba(0,0,0,.05)}.navbar .logo{max-width:100%}@media (max-width:719px){.navbar .logo{max-width:90%}}.navbar .site-name{display:none}.nav-link,.repo-link{font-weight:800}.sidebar-links>li:last-child{margin:0 0 2rem}.icon.outbound{display:none}h1 .header-anchor,h2 .header-anchor,h3 .header-anchor,h4 .header-anchor,h5 .header-anchor,h6 .header-anchor{opacity:1;color:#bbb}h1 .header-anchor:hover,h2 .header-anchor:hover,h3 .header-anchor:hover,h4 .header-anchor:hover,h5 .header-anchor:hover,h6 .header-anchor:hover{text-decoration:none!important}.theme-default-content:not(.custom){padding:4rem 2.5rem 1rem}.theme-default-content img{border-radius:6px;box-shadow:0 2px 4px 0 rgba(0,0,0,.05);zoom:50%}.table-of-contents ul{list-style:none;list-style-position:outside}.table-of-contents>ul{padding-left:0}.table-of-contents>ul>li{padding:0;margin:0}.table-of-contents a:hover{text-decoration:none!important;opacity:.5}.table-of-contents a:active{text-decoration:none!important;opacity:.7}.table-of-contents a:before{content:"# ";color:#bbb;margin-left:-15px;margin-right:3px}.next,.prev{color:#4099de}.custom-block.tip{background-color:#a48cd3}.custom-block.danger,.custom-block.tip,.custom-block.warning{box-shadow:0 2px 4px 0 rgba(0,0,0,.05);border-radius:4px;border:2px solid transparent}.custom-block.tip{border-color:#7c59c0}.custom-block.warning{border-color:#dcc858}.custom-block.danger{border-color:#ff9d9d}.custom-block-title,.custom-block.tip a,.custom-block.tip p{color:#fff}.custom-block.danger a,.custom-block.warning a{color:currentColor}.custom-block a{font-weight:800;text-decoration:underline}.custom-block code{color:#fff;background-color:rgba(0,0,0,.15)}div[class*=language-]{background-color:#fff;-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:subpixel-antialiased;box-shadow:0 2px 4px 0 rgba(0,0,0,.05)}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.7}.theme-default-content pre[class*=language-] code,.theme-default-content pre code{color:#666!important}div[class~=language-php]:before{content:"php"}div[class*=language-]:before{color:rgba(0,0,0,.3)}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#4099de}.token.class-name,.token.constant,.token.property,.token.symbol{color:#a48cd3}.token.boolean,.token.function,.token.number{color:#666}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#4099de}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#bbb}.algolia-docsearch-suggestion--category-header{background-color:#3c4655!important}.algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--highlight{color:#fff!important;font-weight:700;background:none!important;box-shadow:none!important}#nprogress{pointer-events:none}#nprogress .bar{background:#4099de;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #4099de,0 0 5px #4099de;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border-color:#4099de transparent transparent #4099de;border-style:solid;border-width:2px;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.icon.outbound{color:#aaa;display:inline-block;vertical-align:middle;position:relative;top:-1px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.home{padding:3.6rem 2rem 0;max-width:960px;margin:0 auto;display:block}.home .hero{text-align:center}.home .hero img{max-width:100%;max-height:280px;display:block;margin:3rem auto 1.5rem}.home .hero h1{font-size:3rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.8rem auto}.home .hero .description{max-width:35rem;font-size:1.6rem;line-height:1.3;color:#6a8bad}.home .hero .action-button{display:inline-block;font-size:1.2rem;color:#fff;background-color:#4099de;padding:.8rem 1.6rem;border-radius:4px;transition:background-color .1s ease;box-sizing:border-box;border-bottom:1px solid #288cda}.home .hero .action-button:hover{background-color:#53a3e1}.home .features{border-top:1px solid #ddd;padding:1.2rem 0;margin-top:2.5rem;display:flex;flex-wrap:wrap;align-items:flex-start;align-content:stretch;justify-content:space-between}.home .feature{flex-grow:1;flex-basis:30%;max-width:30%}.home .feature h2{font-size:1.4rem;font-weight:500;border-bottom:none;padding-bottom:0;color:#3a5169}.home .feature p{color:#4e6e8e}.home .footer{padding:2.5rem;border-top:1px solid #ddd;text-align:center;color:#4e6e8e}@media (max-width:719px){.home .features{flex-direction:column}.home .feature{max-width:100%;padding:0 2.5rem}}@media (max-width:419px){.home{padding-left:1.5rem;padding-right:1.5rem}.home .hero img{max-height:210px;margin:2rem auto 1.2rem}.home .hero h1{font-size:2rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.2rem auto}.home .hero .description{font-size:1.2rem}.home .hero .action-button{font-size:1rem;padding:.6rem 1.2rem}.home .feature h2{font-size:1.25rem}}.search-box{display:inline-block;position:relative;margin-right:1rem}.search-box input{cursor:text;width:10rem;height:2rem;color:#4e6e8e;display:inline-block;border:1px solid #c7c7c7;border-radius:2rem;font-size:.9rem;line-height:2rem;padding:0 .5rem 0 2rem;outline:none;transition:all .2s ease;background:#fff url(/docs/assets/img/search.83621669.svg) .6rem .5rem no-repeat;background-size:1rem}.search-box input:focus{cursor:auto;border-color:#4099de}.search-box .suggestions{background:#fff;width:20rem;position:absolute;top:2rem;border:1px solid #c7c7c7;border-radius:6px;padding:.4rem;list-style-type:none}.search-box .suggestions.align-right{right:0}.search-box .suggestion{line-height:1.4;padding:.4rem .6rem;border-radius:4px;cursor:pointer}.search-box .suggestion a{white-space:normal;color:#5d82a6}.search-box .suggestion a .page-title{font-weight:600}.search-box .suggestion a .header{font-size:.9em;margin-left:.25em}.search-box .suggestion.focused{background-color:#f3f4f5}.search-box .suggestion.focused a{color:#4099de}@media (max-width:959px){.search-box input{cursor:pointer;width:0;border-color:transparent;position:relative}.search-box input:focus{cursor:text;left:0;width:10rem}}@media (-ms-high-contrast:none){.search-box input{height:2rem}}@media (max-width:959px) and (min-width:719px){.search-box .suggestions{left:0}}@media (max-width:719px){.search-box{margin-right:0}.search-box input{left:1rem}.search-box .suggestions{right:0}}@media (max-width:419px){.search-box .suggestions{width:calc(100vw - 4rem)}.search-box input:focus{width:8rem}}.sidebar-button{cursor:pointer;display:none;width:1.25rem;height:1.25rem;position:absolute;padding:.6rem;top:.6rem;left:1rem}.sidebar-button .icon{display:block;width:1.25rem;height:1.25rem}@media (max-width:719px){.sidebar-button{display:block}}.dropdown-enter,.dropdown-leave-to{height:0!important}.dropdown-wrapper{cursor:pointer}.dropdown-wrapper .dropdown-title,.dropdown-wrapper .mobile-dropdown-title{display:block;font-size:.9rem;font-family:inherit;cursor:inherit;padding:inherit;line-height:1.4rem;background:transparent;border:none;font-weight:500;color:#2c3e50}.dropdown-wrapper .dropdown-title:hover,.dropdown-wrapper .mobile-dropdown-title:hover{border-color:transparent}.dropdown-wrapper .dropdown-title .arrow,.dropdown-wrapper .mobile-dropdown-title .arrow{vertical-align:middle;margin-top:-1px;margin-left:.4rem}.dropdown-wrapper .mobile-dropdown-title{display:none;font-weight:600}.dropdown-wrapper .mobile-dropdown-title font-size inherit:hover{color:#4099de}.dropdown-wrapper .nav-dropdown .dropdown-item{color:inherit;line-height:1.7rem}.dropdown-wrapper .nav-dropdown .dropdown-item h4{margin:.45rem 0 0;border-top:1px solid #eee;padding:1rem 1.5rem .45rem 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper{padding:0;list-style:none}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper .dropdown-subitem{font-size:.9em}.dropdown-wrapper .nav-dropdown .dropdown-item a{display:block;line-height:1.7rem;position:relative;border-bottom:none;font-weight:400;margin-bottom:0;padding:0 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active,.dropdown-wrapper .nav-dropdown .dropdown-item a:hover{color:#4099de}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{content:"";width:0;height:0;border-left:5px solid #4099de;border-top:3px solid transparent;border-bottom:3px solid transparent;position:absolute;top:calc(50% - 2px);left:9px}.dropdown-wrapper .nav-dropdown .dropdown-item:first-child h4{margin-top:0;padding-top:0;border-top:0}@media (max-width:719px){.dropdown-wrapper.open .dropdown-title{margin-bottom:.5rem}.dropdown-wrapper .dropdown-title{display:none}.dropdown-wrapper .mobile-dropdown-title{display:block}.dropdown-wrapper .nav-dropdown{transition:height .1s ease-out;overflow:hidden}.dropdown-wrapper .nav-dropdown .dropdown-item h4{border-top:0;margin-top:0;padding-top:0}.dropdown-wrapper .nav-dropdown .dropdown-item>a,.dropdown-wrapper .nav-dropdown .dropdown-item h4{font-size:15px;line-height:2rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem{font-size:14px;padding-left:1rem}}@media (min-width:719px){.dropdown-wrapper{height:1.8rem}.dropdown-wrapper.open .nav-dropdown,.dropdown-wrapper:hover .nav-dropdown{display:block!important}.dropdown-wrapper.open:blur{display:none}.dropdown-wrapper .nav-dropdown{display:none;height:auto!important;box-sizing:border-box;max-height:calc(100vh - 2.7rem);overflow-y:auto;position:absolute;top:100%;right:0;background-color:#fff;padding:.6rem 0;border:1px solid;border-color:#ddd #ddd #ccc;text-align:left;border-radius:.25rem;white-space:nowrap;margin:0}}.nav-links{display:inline-block}.nav-links a{line-height:1.4rem;color:inherit}.nav-links a.router-link-active,.nav-links a:hover{color:#4099de}.nav-links .nav-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:2rem}.nav-links .nav-item:first-child{margin-left:0}.nav-links .repo-link{margin-left:1.5rem}@media (max-width:719px){.nav-links .nav-item,.nav-links .repo-link{margin-left:0}}@media (min-width:719px){.nav-links a.router-link-active,.nav-links a:hover{color:#2c3e50}.nav-item>a:not(.external).router-link-active,.nav-item>a:not(.external):hover{margin-bottom:-2px;border-bottom:2px solid #4fa1e1}}.navbar{padding:.7rem 1.5rem;line-height:2.2rem}.navbar a,.navbar img,.navbar span{display:inline-block}.navbar .logo{height:2.2rem;min-width:2.2rem;margin-right:.8rem;vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:#2c3e50;position:relative}.navbar .links{padding-left:1.5rem;box-sizing:border-box;background-color:#fff;white-space:nowrap;font-size:.9rem;position:absolute;right:1.5rem;top:.7rem;display:flex}.navbar .links .search-box{flex:0 0 auto;vertical-align:top}@media (max-width:719px){.navbar{padding-left:4rem}.navbar .can-hide{display:none}.navbar .links{padding-left:1.5rem}.navbar .site-name{width:calc(100vw - 9.4rem);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}}.page-edit{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-edit{padding:2rem}}@media (max-width:419px){.page-edit{padding:1.5rem}}.page-edit{padding-top:1rem;padding-bottom:1rem;overflow:auto}.page-edit .edit-link{display:inline-block}.page-edit .edit-link a{color:#4e6e8e;margin-right:.25rem}.page-edit .last-updated{float:right;font-size:.9em}.page-edit .last-updated .prefix{font-weight:500;color:#4e6e8e}.page-edit .last-updated .time{font-weight:400;color:#767676}@media (max-width:719px){.page-edit .edit-link{margin-bottom:.5rem}.page-edit .last-updated{font-size:.8em;float:none;text-align:left}}.page-nav{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-nav{padding:2rem}}@media (max-width:419px){.page-nav{padding:1.5rem}}.page-nav{padding-top:1rem;padding-bottom:0}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid #ddd;padding-top:1rem;overflow:auto}.page-nav .next{float:right}.page{padding-bottom:2rem;display:block}.sidebar-group .sidebar-group{padding-left:.5em}.sidebar-group:not(.collapsable) .sidebar-heading:not(.clickable){cursor:auto;color:inherit}.sidebar-group.is-sub-group{padding-left:0}.sidebar-group.is-sub-group>.sidebar-heading{font-size:.95em;line-height:1.4;font-weight:400;padding-left:2rem}.sidebar-group.is-sub-group>.sidebar-heading:not(.clickable){opacity:.5}.sidebar-group.is-sub-group>.sidebar-group-items{padding-left:1rem}.sidebar-group.is-sub-group>.sidebar-group-items>li>.sidebar-link{font-size:.95em;border-left:none}.sidebar-group.depth-2>.sidebar-heading{border-left:none}.sidebar-heading{color:#2c3e50;transition:color .15s ease;cursor:pointer;font-size:1.1em;font-weight:700;padding:.35rem 1.5rem .35rem 1.25rem;width:100%;box-sizing:border-box;margin:0;border-left:.25rem solid transparent}.sidebar-heading.open,.sidebar-heading:hover{color:inherit}.sidebar-heading .arrow{position:relative;top:-.12em;left:.5em}.sidebar-heading.clickable.active{font-weight:600;color:#4099de;border-left-color:#4099de}.sidebar-heading.clickable:hover{color:#4099de}.sidebar-group-items{transition:height .1s ease-out;font-size:.95em;overflow:hidden}.sidebar .sidebar-sub-headers{padding-left:1rem;font-size:.95em}a.sidebar-link{font-size:1em;font-weight:400;display:inline-block;color:#2c3e50;border-left:.25rem solid transparent;padding:.35rem 1rem .35rem 1.25rem;line-height:1.4;width:100%;box-sizing:border-box}a.sidebar-link:hover{color:#4099de}a.sidebar-link.active{font-weight:600;color:#4099de;border-left-color:#4099de}.sidebar-group a.sidebar-link{padding-left:2rem}.sidebar-sub-headers a.sidebar-link{padding-top:.25rem;padding-bottom:.25rem;border-left:none}.sidebar-sub-headers a.sidebar-link.active{font-weight:500}.sidebar ul{padding:0;margin:0;list-style-type:none}.sidebar a{display:inline-block}.sidebar .nav-links{display:none;border-bottom:1px solid #ddd;padding:.5rem 0 .75rem}.sidebar .nav-links a{font-weight:600}.sidebar .nav-links .nav-item,.sidebar .nav-links .repo-link{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.sidebar>.sidebar-links{padding:1.5rem 0}.sidebar>.sidebar-links>li>a.sidebar-link{font-size:1.1em;line-height:1.7;font-weight:700}.sidebar>.sidebar-links>li:not(:first-child){margin-top:.75rem}@media (max-width:719px){.sidebar .nav-links{display:block}.sidebar .nav-links .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{top:calc(1rem - 2px)}.sidebar>.sidebar-links{padding:1rem 0}}.badge[data-v-15b7b770]{display:inline-block;font-size:14px;height:18px;line-height:18px;border-radius:3px;padding:0 6px;color:#fff}.badge.green[data-v-15b7b770],.badge.tip[data-v-15b7b770],.badge[data-v-15b7b770]{background-color:#42b983}.badge.error[data-v-15b7b770]{background-color:#da5961}.badge.warn[data-v-15b7b770],.badge.warning[data-v-15b7b770],.badge.yellow[data-v-15b7b770]{background-color:#e7c000}.badge+.badge[data-v-15b7b770]{margin-left:5px}.theme-code-group__nav[data-v-deefee04]{margin-bottom:-35px;background-color:#282c34;padding-bottom:22px;border-top-left-radius:6px;border-top-right-radius:6px;padding-left:10px;padding-top:10px}.theme-code-group__ul[data-v-deefee04]{margin:auto 0;padding-left:0;display:inline-flex;list-style:none}.theme-code-group__nav-tab[data-v-deefee04]{border:0;padding:5px;cursor:pointer;background-color:transparent;font-size:.85em;line-height:1.4;color:hsla(0,0%,100%,.9);font-weight:600}.theme-code-group__nav-tab-active[data-v-deefee04]{border-bottom:1px solid #42b983}.pre-blank[data-v-deefee04]{color:#42b983}.theme-code-block[data-v-759a7d02]{display:none}.theme-code-block__active[data-v-759a7d02]{display:block}.theme-code-block>pre[data-v-759a7d02]{background-color:orange} \ No newline at end of file +code[class*=language-],pre[class*=language-]{color:#ccc;background:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}.theme-default-content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:rgba(27,31,35,.05);border-radius:3px}.theme-default-content code .token.deleted{color:#ec5975}.theme-default-content code .token.inserted{color:#4099de}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}.theme-default-content pre[class*=language-] code,.theme-default-content pre code{color:#fff;padding:0;background-color:transparent;border-radius:0}div[class*=language-]{position:relative;background-color:#282c34;border-radius:6px}div[class*=language-] .highlight-lines{-webkit-user-select:none;user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.4}div[class*=language-] .highlight-lines .highlighted{background-color:rgba(0,0,0,.66)}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{background:transparent;position:relative;z-index:1}div[class*=language-]:before{position:absolute;z-index:3;top:.8em;right:1em;font-size:.75rem;color:hsla(0,0%,100%,.4)}div[class*=language-]:not(.line-numbers-mode) .line-numbers-wrapper{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlighted{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{content:" ";position:absolute;z-index:3;left:0;top:0;display:block;width:3.5rem;height:100%;background-color:rgba(0,0,0,.66)}div[class*=language-].line-numbers-mode pre{padding-left:4.5rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers-wrapper{position:absolute;top:0;width:3.5rem;text-align:center;color:hsla(0,0%,100%,.3);padding:1.25rem 0;line-height:1.4}div[class*=language-].line-numbers-mode .line-numbers-wrapper br{-webkit-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number{position:relative;z-index:4;-webkit-user-select:none;user-select:none;font-size:.85em}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;z-index:2;top:0;left:0;width:3.5rem;height:100%;border-radius:6px 0 0 6px;border-right:1px solid rgba(0,0,0,.66);background-color:#282c34}div[class~=language-js]:before{content:"js"}div[class~=language-ts]:before{content:"ts"}div[class~=language-html]:before{content:"html"}div[class~=language-md]:before{content:"md"}div[class~=language-vue]:before{content:"vue"}div[class~=language-css]:before{content:"css"}div[class~=language-sass]:before{content:"sass"}div[class~=language-scss]:before{content:"scss"}div[class~=language-less]:before{content:"less"}div[class~=language-stylus]:before{content:"stylus"}div[class~=language-go]:before{content:"go"}div[class~=language-java]:before{content:"java"}div[class~=language-c]:before{content:"c"}div[class~=language-sh]:before{content:"sh"}div[class~=language-yaml]:before{content:"yaml"}div[class~=language-py]:before{content:"py"}div[class~=language-docker]:before{content:"docker"}div[class~=language-dockerfile]:before{content:"dockerfile"}div[class~=language-makefile]:before{content:"makefile"}div[class~=language-javascript]:before{content:"js"}div[class~=language-typescript]:before{content:"ts"}div[class~=language-markup]:before{content:"html"}div[class~=language-markdown]:before{content:"md"}div[class~=language-json]:before{content:"json"}div[class~=language-ruby]:before{content:"rb"}div[class~=language-python]:before{content:"py"}div[class~=language-bash]:before{content:"sh"}.custom-block .custom-block-title{font-weight:600;margin-bottom:-.4rem}.custom-block.danger,.custom-block.tip,.custom-block.warning{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-block.tip{background-color:#f3f5f7;border-color:#42b983}.custom-block.warning{background-color:rgba(255,229,100,.3);border-color:#e7c000;color:#6b5900}.custom-block.warning .custom-block-title{color:#b29400}.custom-block.warning a{color:#2c3e50}.custom-block.danger{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.custom-block.danger .custom-block-title{color:#900}.custom-block.danger a{color:#2c3e50}.custom-block.details{display:block;position:relative;border-radius:2px;margin:1.6em 0;padding:1.6em;background-color:#eee}.custom-block.details h4{margin-top:0}.custom-block.details figure:last-child,.custom-block.details p:last-child{margin-bottom:0;padding-bottom:0}.custom-block.details summary{outline:none;cursor:pointer}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-bottom:6px solid #ccc}.arrow.down,.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent}.arrow.down{border-top:6px solid #ccc}.arrow.right{border-left:6px solid #ccc}.arrow.left,.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent}.arrow.left{border-right:6px solid #ccc}.theme-default-content:not(.custom){max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.theme-default-content:not(.custom){padding:2rem}}@media (max-width:419px){.theme-default-content:not(.custom){padding:1.5rem}}.table-of-contents .badge{vertical-align:middle}body,html{padding:0;margin:0;background-color:#fff}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:16px;color:#2c3e50}.page{padding-left:20rem}.navbar{z-index:20;right:0;height:3.6rem;background-color:#fff;box-sizing:border-box;border-bottom:1px solid #ddd}.navbar,.sidebar-mask{position:fixed;top:0;left:0}.sidebar-mask{z-index:9;width:100vw;height:100vh;display:none}.sidebar{font-size:16px;background-color:#fff;width:20rem;position:fixed;z-index:10;margin:0;top:3.6rem;left:0;bottom:0;box-sizing:border-box;border-right:1px solid #ddd;overflow-y:auto}.theme-default-content:not(.custom)>:first-child{margin-top:3.6rem}.theme-default-content:not(.custom) a:hover{text-decoration:underline}.theme-default-content:not(.custom) p.demo{padding:1rem 1.5rem;border:1px solid #ddd;border-radius:4px}.theme-default-content:not(.custom) img{max-width:100%}.theme-default-content.custom{padding:0;margin:0}.theme-default-content.custom img{max-width:100%}a{font-weight:500;text-decoration:none}a,p a code{color:#4099de}p a code{font-weight:400}kbd{background:#eee;border:.15rem solid #ddd;border-bottom:.25rem solid #ddd;border-radius:.15rem;padding:0 .15em}blockquote{font-size:1rem;color:#999;border-left:.2rem solid #dfe2e5;margin:1rem 0;padding:.25rem 0 .25rem 1rem}blockquote>p{margin:0}ol,ul{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25}.theme-default-content:not(.custom)>h1,.theme-default-content:not(.custom)>h2,.theme-default-content:not(.custom)>h3,.theme-default-content:not(.custom)>h4,.theme-default-content:not(.custom)>h5,.theme-default-content:not(.custom)>h6{margin-top:-3.1rem;padding-top:4.6rem;margin-bottom:0}.theme-default-content:not(.custom)>h1:first-child,.theme-default-content:not(.custom)>h2:first-child,.theme-default-content:not(.custom)>h3:first-child,.theme-default-content:not(.custom)>h4:first-child,.theme-default-content:not(.custom)>h5:first-child,.theme-default-content:not(.custom)>h6:first-child{margin-top:-1.5rem;margin-bottom:1rem}.theme-default-content:not(.custom)>h1:first-child+.custom-block,.theme-default-content:not(.custom)>h1:first-child+p,.theme-default-content:not(.custom)>h1:first-child+pre,.theme-default-content:not(.custom)>h2:first-child+.custom-block,.theme-default-content:not(.custom)>h2:first-child+p,.theme-default-content:not(.custom)>h2:first-child+pre,.theme-default-content:not(.custom)>h3:first-child+.custom-block,.theme-default-content:not(.custom)>h3:first-child+p,.theme-default-content:not(.custom)>h3:first-child+pre,.theme-default-content:not(.custom)>h4:first-child+.custom-block,.theme-default-content:not(.custom)>h4:first-child+p,.theme-default-content:not(.custom)>h4:first-child+pre,.theme-default-content:not(.custom)>h5:first-child+.custom-block,.theme-default-content:not(.custom)>h5:first-child+p,.theme-default-content:not(.custom)>h5:first-child+pre,.theme-default-content:not(.custom)>h6:first-child+.custom-block,.theme-default-content:not(.custom)>h6:first-child+p,.theme-default-content:not(.custom)>h6:first-child+pre{margin-top:2rem}h1:focus .header-anchor,h1:hover .header-anchor,h2:focus .header-anchor,h2:hover .header-anchor,h3:focus .header-anchor,h3:hover .header-anchor,h4:focus .header-anchor,h4:hover .header-anchor,h5:focus .header-anchor,h5:hover .header-anchor,h6:focus .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2.2rem}h2{font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #ddd}h3{font-size:1.35rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0}a.header-anchor:focus,a.header-anchor:hover{text-decoration:none}.line-number,code,kbd{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}ol,p,ul{line-height:1.7}hr{border:0;border-top:1px solid #ddd}table{border-collapse:collapse;margin:1rem 0;display:block;overflow-x:auto}tr{border-top:1px solid #dfe2e5}tr:nth-child(2n){background-color:#f6f8fa}td,th{border:1px solid #dfe2e5;padding:.6em 1em}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.no-navbar .theme-default-content:not(.custom)>h1,.theme-container.no-navbar h2,.theme-container.no-navbar h3,.theme-container.no-navbar h4,.theme-container.no-navbar h5,.theme-container.no-navbar h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .sidebar{top:0}@media (min-width:720px){.theme-container.no-sidebar .sidebar{display:none}.theme-container.no-sidebar .page{padding-left:0}}@media (max-width:959px){.sidebar{font-size:15px;width:16.4rem}.page{padding-left:16.4rem}}@media (max-width:719px){.sidebar{top:0;padding-top:3.6rem;transform:translateX(-100%);transition:transform .2s ease}.page{padding-left:0}.theme-container.sidebar-open .sidebar{transform:translateX(0)}.theme-container.no-navbar .sidebar{padding-top:0}}@media (max-width:419px){h1{font-size:1.9rem}.theme-default-content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}body{background-color:#eef1f4;font-family:Nunito}h1,h2,h3,h4,h5,h6{font-weight:300}h1{padding-bottom:16px;border-bottom:2px solid rgba(0,0,0,.05)}h2{border-bottom:0}@media (min-width:720px){.page{padding-left:13.75rem}.page-nav{padding:0}.page-nav>.inner{padding:0;border-top:none}}.navbar{z-index:500;border-bottom:none;box-shadow:0 2px 4px 0 rgba(0,0,0,.05)}.navbar .logo{max-width:100%}@media (max-width:719px){.navbar .logo{max-width:90%}}.navbar .site-name{display:none}.nav-link,.repo-link{font-weight:800}.sidebar-links>li:last-child{margin:0 0 2rem}.icon.outbound{display:none}h1 .header-anchor,h2 .header-anchor,h3 .header-anchor,h4 .header-anchor,h5 .header-anchor,h6 .header-anchor{opacity:1;color:#bbb}h1 .header-anchor:hover,h2 .header-anchor:hover,h3 .header-anchor:hover,h4 .header-anchor:hover,h5 .header-anchor:hover,h6 .header-anchor:hover{text-decoration:none!important}.theme-default-content:not(.custom){padding:4rem 2.5rem 1rem}.theme-default-content img{border-radius:6px;box-shadow:0 2px 4px 0 rgba(0,0,0,.05);zoom:50%}.table-of-contents ul{list-style:none;list-style-position:outside}.table-of-contents>ul{padding-left:0}.table-of-contents>ul>li{padding:0;margin:0}.table-of-contents a:hover{text-decoration:none!important;opacity:.5}.table-of-contents a:active{text-decoration:none!important;opacity:.7}.table-of-contents a:before{content:"# ";color:#bbb;margin-left:-15px;margin-right:3px}.next,.prev{color:#4099de}.custom-block.tip{background-color:#a48cd3}.custom-block.danger,.custom-block.tip,.custom-block.warning{box-shadow:0 2px 4px 0 rgba(0,0,0,.05);border-radius:4px;border:2px solid transparent}.custom-block.tip{border-color:#7c59c0}.custom-block.warning{border-color:#dcc858}.custom-block.danger{border-color:#ff9d9d}.custom-block-title,.custom-block.tip a,.custom-block.tip p{color:#fff}.custom-block.danger a,.custom-block.warning a{color:currentColor}.custom-block a{font-weight:800;text-decoration:underline}.custom-block code{color:#fff;background-color:rgba(0,0,0,.15)}div[class*=language-]{background-color:#fff;-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:subpixel-antialiased;box-shadow:0 2px 4px 0 rgba(0,0,0,.05)}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.7}.theme-default-content pre[class*=language-] code,.theme-default-content pre code{color:#666!important}div[class~=language-php]:before{content:"php"}div[class*=language-]:before{color:rgba(0,0,0,.3)}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#4099de}.token.class-name,.token.constant,.token.property,.token.symbol{color:#a48cd3}.token.boolean,.token.function,.token.number{color:#666}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#4099de}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#bbb}.algolia-docsearch-suggestion--category-header{background-color:#3c4655!important}.algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--highlight{color:#fff!important;font-weight:700;background:none!important;box-shadow:none!important}#nprogress{pointer-events:none}#nprogress .bar{background:#4099de;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #4099de,0 0 5px #4099de;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border-color:#4099de transparent transparent #4099de;border-style:solid;border-width:2px;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.icon.outbound{color:#aaa;display:inline-block;vertical-align:middle;position:relative;top:-1px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.home{padding:3.6rem 2rem 0;max-width:960px;margin:0 auto;display:block}.home .hero{text-align:center}.home .hero img{max-width:100%;max-height:280px;display:block;margin:3rem auto 1.5rem}.home .hero h1{font-size:3rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.8rem auto}.home .hero .description{max-width:35rem;font-size:1.6rem;line-height:1.3;color:#6a8bad}.home .hero .action-button{display:inline-block;font-size:1.2rem;color:#fff;background-color:#4099de;padding:.8rem 1.6rem;border-radius:4px;transition:background-color .1s ease;box-sizing:border-box;border-bottom:1px solid #288cda}.home .hero .action-button:hover{background-color:#53a3e1}.home .features{border-top:1px solid #ddd;padding:1.2rem 0;margin-top:2.5rem;display:flex;flex-wrap:wrap;align-items:flex-start;align-content:stretch;justify-content:space-between}.home .feature{flex-grow:1;flex-basis:30%;max-width:30%}.home .feature h2{font-size:1.4rem;font-weight:500;border-bottom:none;padding-bottom:0;color:#3a5169}.home .feature p{color:#4e6e8e}.home .footer{padding:2.5rem;border-top:1px solid #ddd;text-align:center;color:#4e6e8e}@media (max-width:719px){.home .features{flex-direction:column}.home .feature{max-width:100%;padding:0 2.5rem}}@media (max-width:419px){.home{padding-left:1.5rem;padding-right:1.5rem}.home .hero img{max-height:210px;margin:2rem auto 1.2rem}.home .hero h1{font-size:2rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.2rem auto}.home .hero .description{font-size:1.2rem}.home .hero .action-button{font-size:1rem;padding:.6rem 1.2rem}.home .feature h2{font-size:1.25rem}}.search-box{display:inline-block;position:relative;margin-right:1rem}.search-box input{cursor:text;width:10rem;height:2rem;color:#4e6e8e;display:inline-block;border:1px solid #c7c7c7;border-radius:2rem;font-size:.9rem;line-height:2rem;padding:0 .5rem 0 2rem;outline:none;transition:all .2s ease;background:#fff url(/docs/assets/img/search.83621669.svg) .6rem .5rem no-repeat;background-size:1rem}.search-box input:focus{cursor:auto;border-color:#4099de}.search-box .suggestions{background:#fff;width:20rem;position:absolute;top:2rem;border:1px solid #c7c7c7;border-radius:6px;padding:.4rem;list-style-type:none}.search-box .suggestions.align-right{right:0}.search-box .suggestion{line-height:1.4;padding:.4rem .6rem;border-radius:4px;cursor:pointer}.search-box .suggestion a{white-space:normal;color:#5d82a6}.search-box .suggestion a .page-title{font-weight:600}.search-box .suggestion a .header{font-size:.9em;margin-left:.25em}.search-box .suggestion.focused{background-color:#f3f4f5}.search-box .suggestion.focused a{color:#4099de}@media (max-width:959px){.search-box input{cursor:pointer;width:0;border-color:transparent;position:relative}.search-box input:focus{cursor:text;left:0;width:10rem}}@media (-ms-high-contrast:none){.search-box input{height:2rem}}@media (max-width:959px) and (min-width:719px){.search-box .suggestions{left:0}}@media (max-width:719px){.search-box{margin-right:0}.search-box input{left:1rem}.search-box .suggestions{right:0}}@media (max-width:419px){.search-box .suggestions{width:calc(100vw - 4rem)}.search-box input:focus{width:8rem}}.sidebar-button{cursor:pointer;display:none;width:1.25rem;height:1.25rem;position:absolute;padding:.6rem;top:.6rem;left:1rem}.sidebar-button .icon{display:block;width:1.25rem;height:1.25rem}@media (max-width:719px){.sidebar-button{display:block}}.dropdown-enter,.dropdown-leave-to{height:0!important}.dropdown-wrapper{cursor:pointer}.dropdown-wrapper .dropdown-title,.dropdown-wrapper .mobile-dropdown-title{display:block;font-size:.9rem;font-family:inherit;cursor:inherit;padding:inherit;line-height:1.4rem;background:transparent;border:none;font-weight:500;color:#2c3e50}.dropdown-wrapper .dropdown-title:hover,.dropdown-wrapper .mobile-dropdown-title:hover{border-color:transparent}.dropdown-wrapper .dropdown-title .arrow,.dropdown-wrapper .mobile-dropdown-title .arrow{vertical-align:middle;margin-top:-1px;margin-left:.4rem}.dropdown-wrapper .mobile-dropdown-title{display:none;font-weight:600}.dropdown-wrapper .mobile-dropdown-title font-size inherit:hover{color:#4099de}.dropdown-wrapper .nav-dropdown .dropdown-item{color:inherit;line-height:1.7rem}.dropdown-wrapper .nav-dropdown .dropdown-item h4{margin:.45rem 0 0;border-top:1px solid #eee;padding:1rem 1.5rem .45rem 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper{padding:0;list-style:none}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper .dropdown-subitem{font-size:.9em}.dropdown-wrapper .nav-dropdown .dropdown-item a{display:block;line-height:1.7rem;position:relative;border-bottom:none;font-weight:400;margin-bottom:0;padding:0 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active,.dropdown-wrapper .nav-dropdown .dropdown-item a:hover{color:#4099de}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{content:"";width:0;height:0;border-left:5px solid #4099de;border-top:3px solid transparent;border-bottom:3px solid transparent;position:absolute;top:calc(50% - 2px);left:9px}.dropdown-wrapper .nav-dropdown .dropdown-item:first-child h4{margin-top:0;padding-top:0;border-top:0}@media (max-width:719px){.dropdown-wrapper.open .dropdown-title{margin-bottom:.5rem}.dropdown-wrapper .dropdown-title{display:none}.dropdown-wrapper .mobile-dropdown-title{display:block}.dropdown-wrapper .nav-dropdown{transition:height .1s ease-out;overflow:hidden}.dropdown-wrapper .nav-dropdown .dropdown-item h4{border-top:0;margin-top:0;padding-top:0}.dropdown-wrapper .nav-dropdown .dropdown-item>a,.dropdown-wrapper .nav-dropdown .dropdown-item h4{font-size:15px;line-height:2rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem{font-size:14px;padding-left:1rem}}@media (min-width:719px){.dropdown-wrapper{height:1.8rem}.dropdown-wrapper.open .nav-dropdown,.dropdown-wrapper:hover .nav-dropdown{display:block!important}.dropdown-wrapper.open:blur{display:none}.dropdown-wrapper .nav-dropdown{display:none;height:auto!important;box-sizing:border-box;max-height:calc(100vh - 2.7rem);overflow-y:auto;position:absolute;top:100%;right:0;background-color:#fff;padding:.6rem 0;border:1px solid;border-color:#ddd #ddd #ccc;text-align:left;border-radius:.25rem;white-space:nowrap;margin:0}}.nav-links{display:inline-block}.nav-links a{line-height:1.4rem;color:inherit}.nav-links a.router-link-active,.nav-links a:hover{color:#4099de}.nav-links .nav-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:2rem}.nav-links .nav-item:first-child{margin-left:0}.nav-links .repo-link{margin-left:1.5rem}@media (max-width:719px){.nav-links .nav-item,.nav-links .repo-link{margin-left:0}}@media (min-width:719px){.nav-links a.router-link-active,.nav-links a:hover{color:#2c3e50}.nav-item>a:not(.external).router-link-active,.nav-item>a:not(.external):hover{margin-bottom:-2px;border-bottom:2px solid #4fa1e1}}.navbar{padding:.7rem 1.5rem;line-height:2.2rem}.navbar a,.navbar img,.navbar span{display:inline-block}.navbar .logo{height:2.2rem;min-width:2.2rem;margin-right:.8rem;vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:#2c3e50;position:relative}.navbar .links{padding-left:1.5rem;box-sizing:border-box;background-color:#fff;white-space:nowrap;font-size:.9rem;position:absolute;right:1.5rem;top:.7rem;display:flex}.navbar .links .search-box{flex:0 0 auto;vertical-align:top}@media (max-width:719px){.navbar{padding-left:4rem}.navbar .can-hide{display:none}.navbar .links{padding-left:1.5rem}.navbar .site-name{width:calc(100vw - 9.4rem);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}}.page-edit{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-edit{padding:2rem}}@media (max-width:419px){.page-edit{padding:1.5rem}}.page-edit{padding-top:1rem;padding-bottom:1rem;overflow:auto}.page-edit .edit-link{display:inline-block}.page-edit .edit-link a{color:#4e6e8e;margin-right:.25rem}.page-edit .last-updated{float:right;font-size:.9em}.page-edit .last-updated .prefix{font-weight:500;color:#4e6e8e}.page-edit .last-updated .time{font-weight:400;color:#767676}@media (max-width:719px){.page-edit .edit-link{margin-bottom:.5rem}.page-edit .last-updated{font-size:.8em;float:none;text-align:left}}.page-nav{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-nav{padding:2rem}}@media (max-width:419px){.page-nav{padding:1.5rem}}.page-nav{padding-top:1rem;padding-bottom:0}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid #ddd;padding-top:1rem;overflow:auto}.page-nav .next{float:right}.page{padding-bottom:2rem;display:block}.sidebar-group .sidebar-group{padding-left:.5em}.sidebar-group:not(.collapsable) .sidebar-heading:not(.clickable){cursor:auto;color:inherit}.sidebar-group.is-sub-group{padding-left:0}.sidebar-group.is-sub-group>.sidebar-heading{font-size:.95em;line-height:1.4;font-weight:400;padding-left:2rem}.sidebar-group.is-sub-group>.sidebar-heading:not(.clickable){opacity:.5}.sidebar-group.is-sub-group>.sidebar-group-items{padding-left:1rem}.sidebar-group.is-sub-group>.sidebar-group-items>li>.sidebar-link{font-size:.95em;border-left:none}.sidebar-group.depth-2>.sidebar-heading{border-left:none}.sidebar-heading{color:#2c3e50;transition:color .15s ease;cursor:pointer;font-size:1.1em;font-weight:700;padding:.35rem 1.5rem .35rem 1.25rem;width:100%;box-sizing:border-box;margin:0;border-left:.25rem solid transparent}.sidebar-heading.open,.sidebar-heading:hover{color:inherit}.sidebar-heading .arrow{position:relative;top:-.12em;left:.5em}.sidebar-heading.clickable.active{font-weight:600;color:#4099de;border-left-color:#4099de}.sidebar-heading.clickable:hover{color:#4099de}.sidebar-group-items{transition:height .1s ease-out;font-size:.95em;overflow:hidden}.sidebar .sidebar-sub-headers{padding-left:1rem;font-size:.95em}a.sidebar-link{font-size:1em;font-weight:400;display:inline-block;color:#2c3e50;border-left:.25rem solid transparent;padding:.35rem 1rem .35rem 1.25rem;line-height:1.4;width:100%;box-sizing:border-box}a.sidebar-link:hover{color:#4099de}a.sidebar-link.active{font-weight:600;color:#4099de;border-left-color:#4099de}.sidebar-group a.sidebar-link{padding-left:2rem}.sidebar-sub-headers a.sidebar-link{padding-top:.25rem;padding-bottom:.25rem;border-left:none}.sidebar-sub-headers a.sidebar-link.active{font-weight:500}.sidebar ul{padding:0;margin:0;list-style-type:none}.sidebar a{display:inline-block}.sidebar .nav-links{display:none;border-bottom:1px solid #ddd;padding:.5rem 0 .75rem}.sidebar .nav-links a{font-weight:600}.sidebar .nav-links .nav-item,.sidebar .nav-links .repo-link{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.sidebar>.sidebar-links{padding:1.5rem 0}.sidebar>.sidebar-links>li>a.sidebar-link{font-size:1.1em;line-height:1.7;font-weight:700}.sidebar>.sidebar-links>li:not(:first-child){margin-top:.75rem}@media (max-width:719px){.sidebar .nav-links{display:block}.sidebar .nav-links .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{top:calc(1rem - 2px)}.sidebar>.sidebar-links{padding:1rem 0}}.badge[data-v-15b7b770]{display:inline-block;font-size:14px;height:18px;line-height:18px;border-radius:3px;padding:0 6px;color:#fff}.badge.green[data-v-15b7b770],.badge.tip[data-v-15b7b770],.badge[data-v-15b7b770]{background-color:#42b983}.badge.error[data-v-15b7b770]{background-color:#da5961}.badge.warn[data-v-15b7b770],.badge.warning[data-v-15b7b770],.badge.yellow[data-v-15b7b770]{background-color:#e7c000}.badge+.badge[data-v-15b7b770]{margin-left:5px}.theme-code-block[data-v-759a7d02]{display:none}.theme-code-block__active[data-v-759a7d02]{display:block}.theme-code-block>pre[data-v-759a7d02]{background-color:orange}.theme-code-group__nav[data-v-deefee04]{margin-bottom:-35px;background-color:#282c34;padding-bottom:22px;border-top-left-radius:6px;border-top-right-radius:6px;padding-left:10px;padding-top:10px}.theme-code-group__ul[data-v-deefee04]{margin:auto 0;padding-left:0;display:inline-flex;list-style:none}.theme-code-group__nav-tab[data-v-deefee04]{border:0;padding:5px;cursor:pointer;background-color:transparent;font-size:.85em;line-height:1.4;color:hsla(0,0%,100%,.9);font-weight:600}.theme-code-group__nav-tab-active[data-v-deefee04]{border-bottom:1px solid #42b983}.pre-blank[data-v-deefee04]{color:#42b983} \ No newline at end of file diff --git a/.vuepress/dist/assets/js/11.6b26706e.js b/.vuepress/dist/assets/js/11.3605d95f.js similarity index 83% rename from .vuepress/dist/assets/js/11.6b26706e.js rename to .vuepress/dist/assets/js/11.3605d95f.js index d8ef09a..d93e7f4 100644 --- a/.vuepress/dist/assets/js/11.6b26706e.js +++ b/.vuepress/dist/assets/js/11.3605d95f.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{443:function(t,e,n){"use strict";n.r(e);var s=n(55),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("meta",{attrs:{"http-equiv":"refresh",content:"0;url=/docs/1.x/introduction.html"}})])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{406:function(t,e,n){"use strict";n.r(e);var s=n(55),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("meta",{attrs:{"http-equiv":"refresh",content:"0;url=/docs/1.x/introduction.html"}})])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/12.f432fe5b.js b/.vuepress/dist/assets/js/12.965072a7.js similarity index 99% rename from .vuepress/dist/assets/js/12.f432fe5b.js rename to .vuepress/dist/assets/js/12.965072a7.js index ce77121..8e11b65 100644 --- a/.vuepress/dist/assets/js/12.f432fe5b.js +++ b/.vuepress/dist/assets/js/12.965072a7.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{410:function(a,t,s){"use strict";s.r(t);var e=s(55),r=Object(e.a)({},(function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h1",{attrs:{id:"installation"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[a._v("#")]),a._v(" Installation")]),a._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#installing-spark-via-composer"}},[a._v("Installing Spark Via Composer")])]),s("li",[s("a",{attrs:{href:"#authenticating-spark-in-continuous-integration-ci-environments"}},[a._v("Authenticating Spark in Continuous Integration (CI) Environments")])])])]),s("p"),a._v(" "),s("h2",{attrs:{id:"installing-spark-via-composer"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#installing-spark-via-composer"}},[a._v("#")]),a._v(" Installing Spark Via Composer")]),a._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[a._v("License")]),a._v(" "),s("p",[a._v("Before installing Spark, you will need to purchase a "),s("a",{attrs:{href:"https://spark.laravel.com/licenses",target:"_blank",rel:"noopener noreferrer"}},[a._v("Spark license"),s("OutboundLink")],1),a._v(". You can purchase a Spark license via the Spark dashboard.")])]),a._v(" "),s("p",[a._v("To get started installing Spark, add the Spark repository to your application's "),s("code",[a._v("composer.json")]),a._v(" file:")]),a._v(" "),s("div",{staticClass:"language-json extra-class"},[s("pre",{pre:!0,attrs:{class:"language-json"}},[s("code",[s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"repositories"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"composer"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"url"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"https://spark.laravel.com"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n")])])]),s("p",[a._v("Next, you may add the "),s("code",[a._v("laravel/spark-paddle")]),a._v(" or "),s("code",[a._v("laravel/spark-stripe")]),a._v(" package to the list of required packages in your "),s("code",[a._v("composer.json")]),a._v(" file:")]),a._v(" "),s("div",{staticClass:"language-json extra-class"},[s("pre",{pre:!0,attrs:{class:"language-json"}},[s("code",[s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"require"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"php"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^7.3"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"laravel/framework"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^8.0"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"laravel/spark-paddle"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^1.0"')]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n")])])]),s("p",[a._v("After your "),s("code",[a._v("composer.json")]),a._v(" file has been updated, run the "),s("code",[a._v("composer update")]),a._v(" command in your console terminal:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("composer")]),a._v(" update\n")])])]),s("p",[a._v("When running "),s("code",[a._v("composer update")]),a._v(", you will be prompted to provide your login credentials for the Spark website. These credentials will authenticate your Composer session as having permission to download the Spark source code. To avoid manually typing these credentials, you may create a "),s("a",{attrs:{href:"https://getcomposer.org/doc/articles/http-basic-authentication.md",target:"_blank",rel:"noopener noreferrer"}},[a._v("Composer auth.json file"),s("OutboundLink")],1),a._v(" and use your "),s("a",{attrs:{href:"https://spark.laravel.com/user/api-tokens",target:"_blank",rel:"noopener noreferrer"}},[a._v("API token"),s("OutboundLink")],1),a._v(" in place of your password:")]),a._v(" "),s("div",{staticClass:"language-json extra-class"},[s("pre",{pre:!0,attrs:{class:"language-json"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"http-basic"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"spark.laravel.com"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"username"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"taylor@example.com"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"password"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"your-api-token"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("You may quickly create an "),s("code",[a._v("auth.json")]),a._v(" file via your terminal using the following command. As mentioned previously, you may create an API token via the "),s("a",{attrs:{href:"https://spark.laravel.com/user/api-tokens",target:"_blank",rel:"noopener noreferrer"}},[a._v("Spark dashboard"),s("OutboundLink")],1),a._v(". This token may be used as a substitute for your password when creating a Composer "),s("code",[a._v("auth.json")]),a._v(" file:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("composer")]),a._v(" config http-basic.spark.laravel.com taylor@example.com your-api-token\n")])])]),s("div",{staticClass:"custom-block danger"},[s("p",{staticClass:"custom-block-title"},[a._v("The `auth.json` File")]),a._v(" "),s("p",[a._v("You should not commit your application's "),s("code",[a._v("auth.json")]),a._v(" file into source control.")])]),a._v(" "),s("p",[a._v("Once the package is installed via Composer, run the "),s("code",[a._v("spark:install")]),a._v(" Artisan command:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("php artisan spark:install\n")])])]),s("p",[a._v("Finally, run the "),s("code",[a._v("migrate")]),a._v(" Artisan command:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("php artisan migrate\n")])])]),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[a._v("Stripe Billables")]),a._v(" "),s("p",[a._v("If you are using the Stripe edition of Spark and plan to bill a model other than the "),s("code",[a._v("App\\Models\\User")]),a._v(" model, you should follow "),s("RouterLink",{attrs:{to:"/1.x/spark-stripe/customization.html#migrations"}},[a._v("these instructions")]),a._v(" before running the migration command.")],1)]),a._v(" "),s("p",[a._v("That's it! Next, you may navigate to your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file and begin configuring your Spark installation.")]),a._v(" "),s("h2",{attrs:{id:"authenticating-spark-in-continuous-integration-ci-environments"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#authenticating-spark-in-continuous-integration-ci-environments"}},[a._v("#")]),a._v(" Authenticating Spark in Continuous Integration (CI) Environments")]),a._v(" "),s("p",[a._v("It's not advised to store your "),s("code",[a._v("auth.json")]),a._v(" file inside your project's version control repository. However, there may be times you wish to download Spark inside a CI environment like "),s("a",{attrs:{href:"https://chipperci.com/",target:"_blank",rel:"noopener noreferrer"}},[a._v("Chipper CI"),s("OutboundLink")],1),a._v(". For instance, you may wish to run tests for any custom tools you create. To authenticate Spark in these situations, you can use Composer to set the configuration option inside your CI system's pipeline, injecting environment variables containing the credentials you use to login to the Spark dashboard and a valid "),s("a",{attrs:{href:"https://spark.laravel.com/users/api-tokens",target:"_blank",rel:"noopener noreferrer"}},[a._v("Spark dashboard API token"),s("OutboundLink")],1),a._v(":")]),a._v(" "),s("div",{staticClass:"language-sh extra-class"},[s("pre",{pre:!0,attrs:{class:"language-sh"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("composer")]),a._v(" config http-basic.spark.laravel.com "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("${SPARK_USERNAME}")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("${SPARK_API_TOKEN}")]),a._v("\n")])])])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{405:function(a,t,s){"use strict";s.r(t);var e=s(55),r=Object(e.a)({},(function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h1",{attrs:{id:"installation"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[a._v("#")]),a._v(" Installation")]),a._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#installing-spark-via-composer"}},[a._v("Installing Spark Via Composer")])]),s("li",[s("a",{attrs:{href:"#authenticating-spark-in-continuous-integration-ci-environments"}},[a._v("Authenticating Spark in Continuous Integration (CI) Environments")])])])]),s("p"),a._v(" "),s("h2",{attrs:{id:"installing-spark-via-composer"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#installing-spark-via-composer"}},[a._v("#")]),a._v(" Installing Spark Via Composer")]),a._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[a._v("License")]),a._v(" "),s("p",[a._v("Before installing Spark, you will need to purchase a "),s("a",{attrs:{href:"https://spark.laravel.com/licenses",target:"_blank",rel:"noopener noreferrer"}},[a._v("Spark license"),s("OutboundLink")],1),a._v(". You can purchase a Spark license via the Spark dashboard.")])]),a._v(" "),s("p",[a._v("To get started installing Spark, add the Spark repository to your application's "),s("code",[a._v("composer.json")]),a._v(" file:")]),a._v(" "),s("div",{staticClass:"language-json extra-class"},[s("pre",{pre:!0,attrs:{class:"language-json"}},[s("code",[s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"repositories"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"composer"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"url"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"https://spark.laravel.com"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n")])])]),s("p",[a._v("Next, you may add the "),s("code",[a._v("laravel/spark-paddle")]),a._v(" or "),s("code",[a._v("laravel/spark-stripe")]),a._v(" package to the list of required packages in your "),s("code",[a._v("composer.json")]),a._v(" file:")]),a._v(" "),s("div",{staticClass:"language-json extra-class"},[s("pre",{pre:!0,attrs:{class:"language-json"}},[s("code",[s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"require"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"php"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^7.3"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"laravel/framework"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^8.0"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"laravel/spark-paddle"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^1.0"')]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n")])])]),s("p",[a._v("After your "),s("code",[a._v("composer.json")]),a._v(" file has been updated, run the "),s("code",[a._v("composer update")]),a._v(" command in your console terminal:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("composer")]),a._v(" update\n")])])]),s("p",[a._v("When running "),s("code",[a._v("composer update")]),a._v(", you will be prompted to provide your login credentials for the Spark website. These credentials will authenticate your Composer session as having permission to download the Spark source code. To avoid manually typing these credentials, you may create a "),s("a",{attrs:{href:"https://getcomposer.org/doc/articles/http-basic-authentication.md",target:"_blank",rel:"noopener noreferrer"}},[a._v("Composer auth.json file"),s("OutboundLink")],1),a._v(" and use your "),s("a",{attrs:{href:"https://spark.laravel.com/user/api-tokens",target:"_blank",rel:"noopener noreferrer"}},[a._v("API token"),s("OutboundLink")],1),a._v(" in place of your password:")]),a._v(" "),s("div",{staticClass:"language-json extra-class"},[s("pre",{pre:!0,attrs:{class:"language-json"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"http-basic"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"spark.laravel.com"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"username"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"taylor@example.com"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"password"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"your-api-token"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("You may quickly create an "),s("code",[a._v("auth.json")]),a._v(" file via your terminal using the following command. As mentioned previously, you may create an API token via the "),s("a",{attrs:{href:"https://spark.laravel.com/user/api-tokens",target:"_blank",rel:"noopener noreferrer"}},[a._v("Spark dashboard"),s("OutboundLink")],1),a._v(". This token may be used as a substitute for your password when creating a Composer "),s("code",[a._v("auth.json")]),a._v(" file:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("composer")]),a._v(" config http-basic.spark.laravel.com taylor@example.com your-api-token\n")])])]),s("div",{staticClass:"custom-block danger"},[s("p",{staticClass:"custom-block-title"},[a._v("The `auth.json` File")]),a._v(" "),s("p",[a._v("You should not commit your application's "),s("code",[a._v("auth.json")]),a._v(" file into source control.")])]),a._v(" "),s("p",[a._v("Once the package is installed via Composer, run the "),s("code",[a._v("spark:install")]),a._v(" Artisan command:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("php artisan spark:install\n")])])]),s("p",[a._v("Finally, run the "),s("code",[a._v("migrate")]),a._v(" Artisan command:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("php artisan migrate\n")])])]),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[a._v("Stripe Billables")]),a._v(" "),s("p",[a._v("If you are using the Stripe edition of Spark and plan to bill a model other than the "),s("code",[a._v("App\\Models\\User")]),a._v(" model, you should follow "),s("RouterLink",{attrs:{to:"/1.x/spark-stripe/customization.html#migrations"}},[a._v("these instructions")]),a._v(" before running the migration command.")],1)]),a._v(" "),s("p",[a._v("That's it! Next, you may navigate to your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file and begin configuring your Spark installation.")]),a._v(" "),s("h2",{attrs:{id:"authenticating-spark-in-continuous-integration-ci-environments"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#authenticating-spark-in-continuous-integration-ci-environments"}},[a._v("#")]),a._v(" Authenticating Spark in Continuous Integration (CI) Environments")]),a._v(" "),s("p",[a._v("It's not advised to store your "),s("code",[a._v("auth.json")]),a._v(" file inside your project's version control repository. However, there may be times you wish to download Spark inside a CI environment like "),s("a",{attrs:{href:"https://chipperci.com/",target:"_blank",rel:"noopener noreferrer"}},[a._v("Chipper CI"),s("OutboundLink")],1),a._v(". For instance, you may wish to run tests for any custom tools you create. To authenticate Spark in these situations, you can use Composer to set the configuration option inside your CI system's pipeline, injecting environment variables containing the credentials you use to login to the Spark dashboard and a valid "),s("a",{attrs:{href:"https://spark.laravel.com/users/api-tokens",target:"_blank",rel:"noopener noreferrer"}},[a._v("Spark dashboard API token"),s("OutboundLink")],1),a._v(":")]),a._v(" "),s("div",{staticClass:"language-sh extra-class"},[s("pre",{pre:!0,attrs:{class:"language-sh"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("composer")]),a._v(" config http-basic.spark.laravel.com "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("${SPARK_USERNAME}")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("${SPARK_API_TOKEN}")]),a._v("\n")])])])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/32.413bc4f0.js b/.vuepress/dist/assets/js/13.ca148558.js similarity index 99% rename from .vuepress/dist/assets/js/32.413bc4f0.js rename to .vuepress/dist/assets/js/13.ca148558.js index 4b7b736..111c246 100644 --- a/.vuepress/dist/assets/js/32.413bc4f0.js +++ b/.vuepress/dist/assets/js/13.ca148558.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[32],{429:function(e,r,t){"use strict";t.r(r);var a=t(55),o=Object(a.a)({},(function(){var e=this,r=e.$createElement,t=e._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"introduction"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[e._v("#")]),e._v(" Introduction")]),e._v(" "),t("p"),t("div",{staticClass:"table-of-contents"},[t("ul",[t("li",[t("a",{attrs:{href:"#laravel-spark"}},[e._v("Laravel Spark")])]),t("li",[t("a",{attrs:{href:"#supported-payment-providers"}},[e._v("Supported Payment Providers")]),t("ul",[t("li",[t("a",{attrs:{href:"#paddle"}},[e._v("Paddle")])]),t("li",[t("a",{attrs:{href:"#stripe"}},[e._v("Stripe")])])])]),t("li",[t("a",{attrs:{href:"#frequently-asked-questions"}},[e._v("Frequently Asked Questions")])])])]),t("p"),e._v(" "),t("h2",{attrs:{id:"laravel-spark"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#laravel-spark"}},[e._v("#")]),e._v(" Laravel Spark")]),e._v(" "),t("p",[e._v("Laravel Spark is the perfect starting point for your next big idea. When combined with a Laravel application starter kit like "),t("a",{attrs:{href:"https://jetstream.laravel.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Jetstream"),t("OutboundLink")],1),e._v(" or "),t("a",{attrs:{href:"https://laravel.com/docs/starter-kits",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Breeze"),t("OutboundLink")],1),e._v(", or the frontend of your choice, Spark provides a well-designed billing management panel for your application. Spark, which is built on the power of "),t("a",{attrs:{href:"https://laravel.com/docs/billing",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Cashier"),t("OutboundLink")],1),e._v(", allows your customers to subscribe to monthly or yearly billing plans, manage their payment method, update their subscription plans, and download their receipts all from a self-contained, beautifully designed billing portal.")]),e._v(" "),t("iframe",{attrs:{width:"600",height:"337",src:"https://www.youtube.com/embed/-wAmFagQSzI",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:""}}),e._v(" "),t("h2",{attrs:{id:"supported-payment-providers"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#supported-payment-providers"}},[e._v("#")]),e._v(" Supported Payment Providers")]),e._v(" "),t("p",[e._v("Spark supports two payment providers, and purchasing a Spark license grants you the ability to use either of these payment providers. "),t("strong",[e._v("At this time, it is not possible to implement your own custom payment provider when using Spark.")]),e._v(" We'll provide a brief overview of each provider below.")]),e._v(" "),t("h3",{attrs:{id:"paddle"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#paddle"}},[e._v("#")]),e._v(" Paddle")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Paddle"),t("OutboundLink")],1),e._v(" is a robust billing provider that serves as a merchant of record for your application. Paddle removes the burden of tax compliance from your SaaS business by handling the complexity of gathering and paying your VAT for you. In addition, Paddle provides support for accepting payments from your customers via credit card or PayPal, localized pricing, and hosted invoices.")]),e._v(" "),t("p",[e._v("Spark's Paddle support is provided by the underlying "),t("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Cashier Paddle"),t("OutboundLink")],1),e._v(" library.")]),e._v(" "),t("div",{staticClass:"custom-block warning"},[t("p",{staticClass:"custom-block-title"},[e._v("Paddle Account Approval")]),e._v(" "),t("p",[e._v("Your Paddle account must be approved by Paddle before you can begin using Spark. To apply for an account, please visit the "),t("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Paddle website"),t("OutboundLink")],1),e._v(". "),t("strong",[e._v("While you are developing your application, you may use the "),t("a",{attrs:{href:"https://developer.paddle.com/getting-started/sandbox",target:"_blank",rel:"noopener noreferrer"}},[e._v("Paddle Sandbox"),t("OutboundLink")],1)]),e._v(".")])]),e._v(" "),t("h4",{attrs:{id:"limitations"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#limitations"}},[e._v("#")]),e._v(" Limitations")]),e._v(" "),t("p",[e._v("We have listed some known limitations of using the Paddle payment provider below:")]),e._v(" "),t("ul",[t("li",[e._v("When a recurring coupon is used while subscribing to a plan, the coupon discount will be applied on every billing cycle. However, if the subscription's quantity or plan changes, Paddle will remove the coupon from the subscription.")]),e._v(" "),t("li",[e._v("Because Paddle does not allow plan quantity changes during trial periods, the Paddle edition of Spark does not support requiring a credit card up front when beginning a trial. All trial periods are started without a credit card or payment method provided up front during the user's initial registration process.")])]),e._v(" "),t("h3",{attrs:{id:"stripe"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#stripe"}},[e._v("#")]),e._v(" Stripe")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://stripe.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Stripe"),t("OutboundLink")],1),e._v(" is a global leader in payment infrastructure with direct integration with card networks and banks, a fast-improving platform, and battle-tested reliability. In addition, intelligent optimizations help increase revenue across conversion, prevent fraud, and assist with revenue recovery. Finally, Stripe provides a robust sandbox environment for you to test your application's payment system.")]),e._v(" "),t("p",[e._v("Spark's Stripe support is provided by the underlying "),t("a",{attrs:{href:"https://laravel.com/docs/billing",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Cashier Stripe"),t("OutboundLink")],1),e._v(" library.")]),e._v(" "),t("h4",{attrs:{id:"limitations-2"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#limitations-2"}},[e._v("#")]),e._v(" Limitations")]),e._v(" "),t("p",[e._v("We have listed some known limitations of using the Stripe payment provider below:")]),e._v(" "),t("ul",[t("li",[e._v("The Stripe payment provider does not provide a PayPal integration.")])]),e._v(" "),t("h2",{attrs:{id:"frequently-asked-questions"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#frequently-asked-questions"}},[e._v("#")]),e._v(" Frequently Asked Questions")]),e._v(" "),t("h4",{attrs:{id:"is-it-possible-to-upgrade-an-application-from-spark-classic-to-spark"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#is-it-possible-to-upgrade-an-application-from-spark-classic-to-spark"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Is it possible to upgrade an application from Spark Classic to Spark?")])]),e._v(" "),t("p",[e._v("No. However, we will continue to provide bug fixes and security updates to Spark Classic indefinitely.")]),e._v(" "),t("h4",{attrs:{id:"does-spark-support-any-other-payment-providers"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#does-spark-support-any-other-payment-providers"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Does Spark support any other payment providers?")])]),e._v(" "),t("p",[e._v("No. Spark only supports Stripe and Paddle and it is not possible for developers to customize Spark to accept additional providers. If you need to use another payment provider "),t("strong",[e._v("you should not purchase Laravel Spark")]),e._v(".")]),e._v(" "),t("h4",{attrs:{id:"am-i-required-to-use-tailwind-blade-vue-etc-in-order-to-use-spark"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#am-i-required-to-use-tailwind-blade-vue-etc-in-order-to-use-spark"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Am I required to use Tailwind / Blade / Vue / etc. in order to use Spark?")])]),e._v(" "),t("p",[e._v("No. Spark's billing portal is totally isolated from the rest of your Laravel application and includes its own pre-compiled frontend assets. Your own application may be built using the frontend technologies of your choice.")]),e._v(" "),t("h4",{attrs:{id:"why-are-my-customers-presented-with-a-payment-confirmation-screen"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#why-are-my-customers-presented-with-a-payment-confirmation-screen"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Why are my customers presented with a payment confirmation screen?")])]),e._v(" "),t("p",[e._v("Extra verification is sometimes required in order to confirm and process a payment. When this happens, Paddle or Stripe will present a payment confirmation screen. Payment confirmation screens presented by Paddle, Stripe, or Spark may be tailored to a specific bank or card issuer's payment flow and can include additional card confirmation, a temporary small charge, separate device authentication, or other forms of verification.")])])}),[],!1,null,null,null);r.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{408:function(e,r,t){"use strict";t.r(r);var a=t(55),o=Object(a.a)({},(function(){var e=this,r=e.$createElement,t=e._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"introduction"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[e._v("#")]),e._v(" Introduction")]),e._v(" "),t("p"),t("div",{staticClass:"table-of-contents"},[t("ul",[t("li",[t("a",{attrs:{href:"#laravel-spark"}},[e._v("Laravel Spark")])]),t("li",[t("a",{attrs:{href:"#supported-payment-providers"}},[e._v("Supported Payment Providers")]),t("ul",[t("li",[t("a",{attrs:{href:"#paddle"}},[e._v("Paddle")])]),t("li",[t("a",{attrs:{href:"#stripe"}},[e._v("Stripe")])])])]),t("li",[t("a",{attrs:{href:"#frequently-asked-questions"}},[e._v("Frequently Asked Questions")])])])]),t("p"),e._v(" "),t("h2",{attrs:{id:"laravel-spark"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#laravel-spark"}},[e._v("#")]),e._v(" Laravel Spark")]),e._v(" "),t("p",[e._v("Laravel Spark is the perfect starting point for your next big idea. When combined with a Laravel application starter kit like "),t("a",{attrs:{href:"https://jetstream.laravel.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Jetstream"),t("OutboundLink")],1),e._v(" or "),t("a",{attrs:{href:"https://laravel.com/docs/starter-kits",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Breeze"),t("OutboundLink")],1),e._v(", or the frontend of your choice, Spark provides a well-designed billing management panel for your application. Spark, which is built on the power of "),t("a",{attrs:{href:"https://laravel.com/docs/billing",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Cashier"),t("OutboundLink")],1),e._v(", allows your customers to subscribe to monthly or yearly billing plans, manage their payment method, update their subscription plans, and download their receipts all from a self-contained, beautifully designed billing portal.")]),e._v(" "),t("iframe",{attrs:{width:"600",height:"337",src:"https://www.youtube.com/embed/-wAmFagQSzI",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:""}}),e._v(" "),t("h2",{attrs:{id:"supported-payment-providers"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#supported-payment-providers"}},[e._v("#")]),e._v(" Supported Payment Providers")]),e._v(" "),t("p",[e._v("Spark supports two payment providers, and purchasing a Spark license grants you the ability to use either of these payment providers. "),t("strong",[e._v("At this time, it is not possible to implement your own custom payment provider when using Spark.")]),e._v(" We'll provide a brief overview of each provider below.")]),e._v(" "),t("h3",{attrs:{id:"paddle"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#paddle"}},[e._v("#")]),e._v(" Paddle")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Paddle"),t("OutboundLink")],1),e._v(" is a robust billing provider that serves as a merchant of record for your application. Paddle removes the burden of tax compliance from your SaaS business by handling the complexity of gathering and paying your VAT for you. In addition, Paddle provides support for accepting payments from your customers via credit card or PayPal, localized pricing, and hosted invoices.")]),e._v(" "),t("p",[e._v("Spark's Paddle support is provided by the underlying "),t("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Cashier Paddle"),t("OutboundLink")],1),e._v(" library.")]),e._v(" "),t("div",{staticClass:"custom-block warning"},[t("p",{staticClass:"custom-block-title"},[e._v("Paddle Account Approval")]),e._v(" "),t("p",[e._v("Your Paddle account must be approved by Paddle before you can begin using Spark. To apply for an account, please visit the "),t("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Paddle website"),t("OutboundLink")],1),e._v(". "),t("strong",[e._v("While you are developing your application, you may use the "),t("a",{attrs:{href:"https://developer.paddle.com/getting-started/sandbox",target:"_blank",rel:"noopener noreferrer"}},[e._v("Paddle Sandbox"),t("OutboundLink")],1)]),e._v(".")])]),e._v(" "),t("h4",{attrs:{id:"limitations"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#limitations"}},[e._v("#")]),e._v(" Limitations")]),e._v(" "),t("p",[e._v("We have listed some known limitations of using the Paddle payment provider below:")]),e._v(" "),t("ul",[t("li",[e._v("When a recurring coupon is used while subscribing to a plan, the coupon discount will be applied on every billing cycle. However, if the subscription's quantity or plan changes, Paddle will remove the coupon from the subscription.")]),e._v(" "),t("li",[e._v("Because Paddle does not allow plan quantity changes during trial periods, the Paddle edition of Spark does not support requiring a credit card up front when beginning a trial. All trial periods are started without a credit card or payment method provided up front during the user's initial registration process.")])]),e._v(" "),t("h3",{attrs:{id:"stripe"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#stripe"}},[e._v("#")]),e._v(" Stripe")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://stripe.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Stripe"),t("OutboundLink")],1),e._v(" is a global leader in payment infrastructure with direct integration with card networks and banks, a fast-improving platform, and battle-tested reliability. In addition, intelligent optimizations help increase revenue across conversion, prevent fraud, and assist with revenue recovery. Finally, Stripe provides a robust sandbox environment for you to test your application's payment system.")]),e._v(" "),t("p",[e._v("Spark's Stripe support is provided by the underlying "),t("a",{attrs:{href:"https://laravel.com/docs/billing",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Cashier Stripe"),t("OutboundLink")],1),e._v(" library.")]),e._v(" "),t("h4",{attrs:{id:"limitations-2"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#limitations-2"}},[e._v("#")]),e._v(" Limitations")]),e._v(" "),t("p",[e._v("We have listed some known limitations of using the Stripe payment provider below:")]),e._v(" "),t("ul",[t("li",[e._v("The Stripe payment provider does not provide a PayPal integration.")])]),e._v(" "),t("h2",{attrs:{id:"frequently-asked-questions"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#frequently-asked-questions"}},[e._v("#")]),e._v(" Frequently Asked Questions")]),e._v(" "),t("h4",{attrs:{id:"is-it-possible-to-upgrade-an-application-from-spark-classic-to-spark"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#is-it-possible-to-upgrade-an-application-from-spark-classic-to-spark"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Is it possible to upgrade an application from Spark Classic to Spark?")])]),e._v(" "),t("p",[e._v("No. However, we will continue to provide bug fixes and security updates to Spark Classic indefinitely.")]),e._v(" "),t("h4",{attrs:{id:"does-spark-support-any-other-payment-providers"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#does-spark-support-any-other-payment-providers"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Does Spark support any other payment providers?")])]),e._v(" "),t("p",[e._v("No. Spark only supports Stripe and Paddle and it is not possible for developers to customize Spark to accept additional providers. If you need to use another payment provider "),t("strong",[e._v("you should not purchase Laravel Spark")]),e._v(".")]),e._v(" "),t("h4",{attrs:{id:"am-i-required-to-use-tailwind-blade-vue-etc-in-order-to-use-spark"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#am-i-required-to-use-tailwind-blade-vue-etc-in-order-to-use-spark"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Am I required to use Tailwind / Blade / Vue / etc. in order to use Spark?")])]),e._v(" "),t("p",[e._v("No. Spark's billing portal is totally isolated from the rest of your Laravel application and includes its own pre-compiled frontend assets. Your own application may be built using the frontend technologies of your choice.")]),e._v(" "),t("h4",{attrs:{id:"why-are-my-customers-presented-with-a-payment-confirmation-screen"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#why-are-my-customers-presented-with-a-payment-confirmation-screen"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Why are my customers presented with a payment confirmation screen?")])]),e._v(" "),t("p",[e._v("Extra verification is sometimes required in order to confirm and process a payment. When this happens, Paddle or Stripe will present a payment confirmation screen. Payment confirmation screens presented by Paddle, Stripe, or Spark may be tailored to a specific bank or card issuer's payment flow and can include additional card confirmation, a temporary small charge, separate device authentication, or other forms of verification.")])])}),[],!1,null,null,null);r.default=o.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/14.94f4369e.js b/.vuepress/dist/assets/js/14.382f113d.js similarity index 84% rename from .vuepress/dist/assets/js/14.94f4369e.js rename to .vuepress/dist/assets/js/14.382f113d.js index 2094961..d51e78c 100644 --- a/.vuepress/dist/assets/js/14.94f4369e.js +++ b/.vuepress/dist/assets/js/14.382f113d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{411:function(t,e,n){"use strict";n.r(e);var s=n(55),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("meta",{attrs:{"http-equiv":"refresh",content:"0;url=/docs/1.x/spark-paddle/configuration.html"}})])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{407:function(t,e,n){"use strict";n.r(e);var s=n(55),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("meta",{attrs:{"http-equiv":"refresh",content:"0;url=/docs/1.x/spark-paddle/configuration.html"}})])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/15.65efddc6.js b/.vuepress/dist/assets/js/15.be446089.js similarity index 99% rename from .vuepress/dist/assets/js/15.65efddc6.js rename to .vuepress/dist/assets/js/15.be446089.js index bb81dd0..321ee87 100644 --- a/.vuepress/dist/assets/js/15.65efddc6.js +++ b/.vuepress/dist/assets/js/15.be446089.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{406:function(a,t,s){"use strict";s.r(t);var e=s(55),n=Object(e.a)({},(function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h1",{attrs:{id:"configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuration"}},[a._v("#")]),a._v(" Configuration")]),a._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#introduction"}},[a._v("Introduction")])]),s("li",[s("a",{attrs:{href:"#paddle-configuration"}},[a._v("Paddle Configuration")]),s("ul",[s("li",[s("a",{attrs:{href:"#environment-variables"}},[a._v("Environment Variables")])]),s("li",[s("a",{attrs:{href:"#paddle-webhooks"}},[a._v("Paddle Webhooks")])])])]),s("li",[s("a",{attrs:{href:"#configuring-billables"}},[a._v("Configuring Billables")]),s("ul",[s("li",[s("a",{attrs:{href:"#billable-slugs"}},[a._v("Billable Slugs")])]),s("li",[s("a",{attrs:{href:"#billable-resolution"}},[a._v("Billable Resolution")])]),s("li",[s("a",{attrs:{href:"#billable-authorization"}},[a._v("Billable Authorization")])]),s("li",[s("a",{attrs:{href:"#billable-email-address"}},[a._v("Billable Email Address")])])])]),s("li",[s("a",{attrs:{href:"#defining-subscription-plans"}},[a._v("Defining Subscription Plans")])]),s("li",[s("a",{attrs:{href:"#accessing-the-billing-portal"}},[a._v("Accessing The Billing Portal")])]),s("li",[s("a",{attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[a._v("Showing A Link To The Terms And Conditions")])])])]),s("p"),a._v(" "),s("h2",{attrs:{id:"introduction"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[a._v("#")]),a._v(" Introduction")]),a._v(" "),s("p",[a._v("In the following documentation, we will discuss how to configure a Laravel Spark installation when using the "),s("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[a._v("Paddle"),s("OutboundLink")],1),a._v(" payment provider. All of Spark's configuration options are housed in your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file.")]),a._v(" "),s("h2",{attrs:{id:"paddle-configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#paddle-configuration"}},[a._v("#")]),a._v(" Paddle Configuration")]),a._v(" "),s("p",[a._v("Of course, to use Paddle as a payment provider for your Laravel Spark application you must have an active "),s("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[a._v("Paddle account"),s("OutboundLink")],1),a._v(". "),s("strong",[a._v("While you are developing your application, you may use the "),s("a",{attrs:{href:"https://developer.paddle.com/getting-started/sandbox",target:"_blank",rel:"noopener noreferrer"}},[a._v("Paddle Sandbox"),s("OutboundLink")],1)]),a._v(".")]),a._v(" "),s("h3",{attrs:{id:"environment-variables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#environment-variables"}},[a._v("#")]),a._v(" Environment Variables")]),a._v(" "),s("p",[a._v("Next, you should configure the application environment variables that will be needed by Spark in order to access your Paddle account. These variables should be placed in your application's "),s("code",[a._v(".env")]),a._v(" environment file.")]),a._v(" "),s("p",[a._v("Of course, you should adjust the variable's values to correspond to your own Paddle account's credentials. In addition, you should set the "),s("code",[a._v("PADDLE_SANDBOX")]),a._v(" variable to "),s("code",[a._v("true")]),a._v(' if you are using Paddle\'s sandbox environment. Your Paddle API credentials and public key are available in your Paddle account dashboard via the "Developer Tools" section\'s "Authentication", "Public Key", and "SDK API" panels:')]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("CASHIER_CURRENCY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("USD\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("CASHIER_CURRENCY_LOCALE")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("en\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_SANDBOX")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("true\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_VENDOR_ID")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("your-paddle-vendor-id\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_VENDOR_AUTH_CODE")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("your-paddle-vendor-auth-code\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_PUBLIC_KEY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"-----BEGIN PUBLIC KEY-----\nMIICIjANBiuqhiiG9w0BAQEFXAOCAg8AMIIjjgKCAraAyj/UyC89sqpOnpEZcM76\nguppK9vfF7balLj87rE9VXq5...EAAQ==\n-----END PUBLIC KEY-----"')]),a._v("\n")])])]),s("div",{staticClass:"custom-block danger"},[s("p",{staticClass:"custom-block-title"},[a._v("Configuring Locales")]),a._v(" "),s("p",[a._v("In order to use locales other than "),s("code",[a._v("en")]),a._v(", ensure the "),s("code",[a._v("ext-intl")]),a._v(" PHP extension is installed and configured on your server.")])]),a._v(" "),s("h3",{attrs:{id:"paddle-webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#paddle-webhooks"}},[a._v("#")]),a._v(" Paddle Webhooks")]),a._v(" "),s("p",[a._v("In addition, your Spark powered application will need to receive webhooks from Paddle in order to keep your application's billing and subscription data in sync with Paddle's. Within your Paddle dashboard's \"Alerts / Webhooks\" management panel, you should configure Paddle to send webhook alerts to your application's "),s("code",[a._v("/spark/webhook")]),a._v(" URI. You should enable webhook alerts for the following events:")]),a._v(" "),s("ul",[s("li",[a._v("Subscription Created")]),a._v(" "),s("li",[a._v("Subscription Updated")]),a._v(" "),s("li",[a._v("Subscription Cancelled")]),a._v(" "),s("li",[a._v("Subscription Payment Success")]),a._v(" "),s("li",[a._v("Subscription Payment Failed")]),a._v(" "),s("li",[a._v("High Risk Transaction Created")]),a._v(" "),s("li",[a._v("High Risk Transaction Updated")])]),a._v(" "),s("h4",{attrs:{id:"webhooks-local-development"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks-local-development"}},[a._v("#")]),a._v(" Webhooks & Local Development")]),a._v(" "),s("p",[a._v("For Paddle to be able to send your application webhooks during local development, you will need to expose your application via a site sharing service such as "),s("a",{attrs:{href:"https://ngrok.io",target:"_blank",rel:"noopener noreferrer"}},[a._v("Ngrok"),s("OutboundLink")],1),a._v(" or "),s("a",{attrs:{href:"https://beyondco.de/docs/expose/introduction",target:"_blank",rel:"noopener noreferrer"}},[a._v("Expose"),s("OutboundLink")],1),a._v(". If you are developing your application locally using "),s("a",{attrs:{href:"http://laravel.com/docs/sail",target:"_blank",rel:"noopener noreferrer"}},[a._v("Laravel Sail"),s("OutboundLink")],1),a._v(", you may use Sail's "),s("a",{attrs:{href:"https://laravel.com/docs/sail#sharing-your-site",target:"_blank",rel:"noopener noreferrer"}},[a._v("site sharing command"),s("OutboundLink")],1),a._v(".")]),a._v(" "),s("h2",{attrs:{id:"configuring-billables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuring-billables"}},[a._v("#")]),a._v(" Configuring Billables")]),a._v(" "),s("p",[a._v("Spark allows you to define the types of billable models that your application will be managing. Most commonly, applications bill individual users for monthly and yearly subscription plans. However, your application may choose to bill some other type of model, such as a team, organization, band, etc.")]),a._v(" "),s("p",[a._v("You may define your billable models within the "),s("code",[a._v("billables")]),a._v(" array of your application's "),s("code",[a._v("spark")]),a._v(" configuration file. By default, this array contains an entry for the "),s("code",[a._v("App\\Models\\User")]),a._v(" model.")]),a._v(" "),s("p",[a._v("Before continuing, you should ensure that the model class that corresponds to your billable model is using the "),s("code",[a._v("Spark\\Billable")]),a._v(" trait:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[a._v("")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("p",[a._v("However, if your application is not billing individual users, you may need to adjust this callback. For example, if your application offers team billing instead of user billing, you might customize the callback like so:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("currentTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("h3",{attrs:{id:"billable-authorization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-authorization"}},[a._v("#")]),a._v(" Billable Authorization")]),a._v(" "),s("p",[a._v("Next, let's examine the authorization callbacks that Spark will use to determine if the currently authenticated user of your application is authorized to view the billing portal for a particular billable model.")]),a._v(" "),s("p",[a._v("When you installed Laravel Spark, an "),s("code",[a._v("App\\Providers\\SparkServiceProvider")]),a._v(" class was created for you. Within this service provider, you will find the authorization callback definition used to determine if a given user is authorized to view the billing portal for the "),s("code",[a._v("App\\Models\\User")]),a._v(" billable class. Of course, if your application is not billing users, you should update the billable class and authorization callback logic to fit your application's needs. By default, Spark will simply verify that the currently authenticated user can only manage its own billing settings:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("User")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&&")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("id")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("==")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("p",[a._v("If the authorization callback returns "),s("code",[a._v("true")]),a._v(", the currently authenticated user will be authorized to view the billing portal and manage the billing settings for the given "),s("code",[a._v("$billable")]),a._v(" model. If the callback returns "),s("code",[a._v("false")]),a._v(", the request to access the billing portal will be denied.")]),a._v(" "),s("p",[a._v("You are free to customize the "),s("code",[a._v("authorize")]),a._v(" callback based on your own application's needs. For example, if your application bills teams instead of individual users, you might update the callback like so:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Team")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&&")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("ownsTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("h3",{attrs:{id:"billable-email-address"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-email-address"}},[a._v("#")]),a._v(" Billable Email Address")]),a._v(" "),s("p",[a._v("By default, Spark will use your billable model's "),s("code",[a._v("email")]),a._v(" attribute as the email address associated with the Paddle customer record it creates for the model. If you would like to specify another attribute that should be used instead, you may define a "),s("code",[a._v("paddleEmail")]),a._v(" method on your billable model:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("/**\n * Get the email address that should be associated with the Paddle customer.\n *\n * @return string\n */")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("public")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[a._v("paddleEmail")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$this")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("email")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("h2",{attrs:{id:"defining-subscription-plans"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#defining-subscription-plans"}},[a._v("#")]),a._v(" Defining Subscription Plans")]),a._v(" "),s("p",[a._v("As we previously discussed, Spark allows you to define the types of billable models that your application will be managing. These billable models are defined within the "),s("code",[a._v("billables")]),a._v(" array of your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file:")]),a._v(" "),s("p",[a._v("Each billable configuration within the "),s("code",[a._v("billables")]),a._v(" array contains a "),s("code",[a._v("plans")]),a._v(" array. Within this array you may configure each of the billing plans offered by your application to that particular billable type. "),s("strong",[a._v("The "),s("code",[a._v("monthly_id")]),a._v(" and "),s("code",[a._v("yearly_id")]),a._v(" identifiers should correspond to the plan identifiers associated with the subscription plan within your Paddle account dashboard:")])]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'billables'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'user'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'model'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'trial_days'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'plans'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'name'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Standard'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'short_description'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'This is a short, human friendly description of the plan.'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'monthly_id'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("env")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'SPARK_STANDARD_MONTHLY_PLAN'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'yearly_id'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("env")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'SPARK_STANDARD_YEARLY_PLAN'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("1001")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'features'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Feature 1'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Feature 2'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Feature 3'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v("\n")])])]),s("p",[a._v("If your subscription plan only offers a monthly billing cycle, you may omit the "),s("code",[a._v("yearly_id")]),a._v(" identifier from your plan configuration. Likewise, if your plan only offers a yearly billing cycle, you may omit the "),s("code",[a._v("monthly_id")]),a._v(" identifier.")]),a._v(" "),s("p",[a._v("In addition, you are free to supply a short description of the plan and a list of features relevant to the plan. This information will be displayed in the Spark billing portal.")]),a._v(" "),s("h2",{attrs:{id:"accessing-the-billing-portal"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#accessing-the-billing-portal"}},[a._v("#")]),a._v(" Accessing The Billing Portal")]),a._v(" "),s("p",[a._v("Once you have configured your Spark installation, you may access your application's billing portal at the "),s("code",[a._v("/billing")]),a._v(" URI. So, if your application is being served on "),s("code",[a._v("localhost")]),a._v(", you may access your application's billing portal at "),s("code",[a._v("http://localhost/billing")]),a._v(".")]),a._v(" "),s("p",[a._v("Of course, you may link to the billing portal from your application's dashboard however you see fit:")]),a._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("a")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("href")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v('"')]),a._v("/billing"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("\n Manage Subscription\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n")])])]),s("h4",{attrs:{id:"billing-portal-multiple-billables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billing-portal-multiple-billables"}},[a._v("#")]),a._v(" Billing Portal & Multiple Billables")]),a._v(" "),s("p",[a._v("If your application is billing more than one type of billable, you should add the billable type's "),s("a",{attrs:{href:"#billable-slugs"}},[a._v("slug")]),a._v(" to the "),s("code",[a._v("/billing")]),a._v(" URI. For example, if you have configured a "),s("code",[a._v("team")]),a._v(" billable type in addition to your "),s("code",[a._v("user")]),a._v(" billable type, you may access the billing portal for teams by navigating to "),s("code",[a._v("http://localhost/billing/team")]),a._v(". However, this typically should not be necessary because most applications will only ever bill one type of model.")]),a._v(" "),s("h2",{attrs:{id:"showing-a-link-to-the-terms-and-conditions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[a._v("#")]),a._v(" Showing A Link To The Terms And Conditions")]),a._v(" "),s("p",[a._v("Many applications display billing terms and conditions during checkout. Spark allows you to easily do the same within your application's billing portal. To get started, add a "),s("code",[a._v("terms_url")]),a._v(" configuration value in your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'terms_url'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'/terms'")]),a._v("\n")])])]),s("p",[a._v("Once added, Spark will display a link pointing to "),s("code",[a._v("/terms")]),a._v(" in the billing portal.")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{409:function(a,t,s){"use strict";s.r(t);var e=s(55),n=Object(e.a)({},(function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h1",{attrs:{id:"configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuration"}},[a._v("#")]),a._v(" Configuration")]),a._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#introduction"}},[a._v("Introduction")])]),s("li",[s("a",{attrs:{href:"#paddle-configuration"}},[a._v("Paddle Configuration")]),s("ul",[s("li",[s("a",{attrs:{href:"#environment-variables"}},[a._v("Environment Variables")])]),s("li",[s("a",{attrs:{href:"#paddle-webhooks"}},[a._v("Paddle Webhooks")])])])]),s("li",[s("a",{attrs:{href:"#configuring-billables"}},[a._v("Configuring Billables")]),s("ul",[s("li",[s("a",{attrs:{href:"#billable-slugs"}},[a._v("Billable Slugs")])]),s("li",[s("a",{attrs:{href:"#billable-resolution"}},[a._v("Billable Resolution")])]),s("li",[s("a",{attrs:{href:"#billable-authorization"}},[a._v("Billable Authorization")])]),s("li",[s("a",{attrs:{href:"#billable-email-address"}},[a._v("Billable Email Address")])])])]),s("li",[s("a",{attrs:{href:"#defining-subscription-plans"}},[a._v("Defining Subscription Plans")])]),s("li",[s("a",{attrs:{href:"#accessing-the-billing-portal"}},[a._v("Accessing The Billing Portal")])]),s("li",[s("a",{attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[a._v("Showing A Link To The Terms And Conditions")])])])]),s("p"),a._v(" "),s("h2",{attrs:{id:"introduction"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[a._v("#")]),a._v(" Introduction")]),a._v(" "),s("p",[a._v("In the following documentation, we will discuss how to configure a Laravel Spark installation when using the "),s("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[a._v("Paddle"),s("OutboundLink")],1),a._v(" payment provider. All of Spark's configuration options are housed in your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file.")]),a._v(" "),s("h2",{attrs:{id:"paddle-configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#paddle-configuration"}},[a._v("#")]),a._v(" Paddle Configuration")]),a._v(" "),s("p",[a._v("Of course, to use Paddle as a payment provider for your Laravel Spark application you must have an active "),s("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[a._v("Paddle account"),s("OutboundLink")],1),a._v(". "),s("strong",[a._v("While you are developing your application, you may use the "),s("a",{attrs:{href:"https://developer.paddle.com/getting-started/sandbox",target:"_blank",rel:"noopener noreferrer"}},[a._v("Paddle Sandbox"),s("OutboundLink")],1)]),a._v(".")]),a._v(" "),s("h3",{attrs:{id:"environment-variables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#environment-variables"}},[a._v("#")]),a._v(" Environment Variables")]),a._v(" "),s("p",[a._v("Next, you should configure the application environment variables that will be needed by Spark in order to access your Paddle account. These variables should be placed in your application's "),s("code",[a._v(".env")]),a._v(" environment file.")]),a._v(" "),s("p",[a._v("Of course, you should adjust the variable's values to correspond to your own Paddle account's credentials. In addition, you should set the "),s("code",[a._v("PADDLE_SANDBOX")]),a._v(" variable to "),s("code",[a._v("true")]),a._v(' if you are using Paddle\'s sandbox environment. Your Paddle API credentials and public key are available in your Paddle account dashboard via the "Developer Tools" section\'s "Authentication", "Public Key", and "SDK API" panels:')]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("CASHIER_CURRENCY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("USD\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("CASHIER_CURRENCY_LOCALE")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("en\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_SANDBOX")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("true\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_VENDOR_ID")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("your-paddle-vendor-id\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_VENDOR_AUTH_CODE")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("your-paddle-vendor-auth-code\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_PUBLIC_KEY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"-----BEGIN PUBLIC KEY-----\nMIICIjANBiuqhiiG9w0BAQEFXAOCAg8AMIIjjgKCAraAyj/UyC89sqpOnpEZcM76\nguppK9vfF7balLj87rE9VXq5...EAAQ==\n-----END PUBLIC KEY-----"')]),a._v("\n")])])]),s("div",{staticClass:"custom-block danger"},[s("p",{staticClass:"custom-block-title"},[a._v("Configuring Locales")]),a._v(" "),s("p",[a._v("In order to use locales other than "),s("code",[a._v("en")]),a._v(", ensure the "),s("code",[a._v("ext-intl")]),a._v(" PHP extension is installed and configured on your server.")])]),a._v(" "),s("h3",{attrs:{id:"paddle-webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#paddle-webhooks"}},[a._v("#")]),a._v(" Paddle Webhooks")]),a._v(" "),s("p",[a._v("In addition, your Spark powered application will need to receive webhooks from Paddle in order to keep your application's billing and subscription data in sync with Paddle's. Within your Paddle dashboard's \"Alerts / Webhooks\" management panel, you should configure Paddle to send webhook alerts to your application's "),s("code",[a._v("/spark/webhook")]),a._v(" URI. You should enable webhook alerts for the following events:")]),a._v(" "),s("ul",[s("li",[a._v("Subscription Created")]),a._v(" "),s("li",[a._v("Subscription Updated")]),a._v(" "),s("li",[a._v("Subscription Cancelled")]),a._v(" "),s("li",[a._v("Subscription Payment Success")]),a._v(" "),s("li",[a._v("Subscription Payment Failed")]),a._v(" "),s("li",[a._v("High Risk Transaction Created")]),a._v(" "),s("li",[a._v("High Risk Transaction Updated")])]),a._v(" "),s("h4",{attrs:{id:"webhooks-local-development"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks-local-development"}},[a._v("#")]),a._v(" Webhooks & Local Development")]),a._v(" "),s("p",[a._v("For Paddle to be able to send your application webhooks during local development, you will need to expose your application via a site sharing service such as "),s("a",{attrs:{href:"https://ngrok.io",target:"_blank",rel:"noopener noreferrer"}},[a._v("Ngrok"),s("OutboundLink")],1),a._v(" or "),s("a",{attrs:{href:"https://beyondco.de/docs/expose/introduction",target:"_blank",rel:"noopener noreferrer"}},[a._v("Expose"),s("OutboundLink")],1),a._v(". If you are developing your application locally using "),s("a",{attrs:{href:"http://laravel.com/docs/sail",target:"_blank",rel:"noopener noreferrer"}},[a._v("Laravel Sail"),s("OutboundLink")],1),a._v(", you may use Sail's "),s("a",{attrs:{href:"https://laravel.com/docs/sail#sharing-your-site",target:"_blank",rel:"noopener noreferrer"}},[a._v("site sharing command"),s("OutboundLink")],1),a._v(".")]),a._v(" "),s("h2",{attrs:{id:"configuring-billables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuring-billables"}},[a._v("#")]),a._v(" Configuring Billables")]),a._v(" "),s("p",[a._v("Spark allows you to define the types of billable models that your application will be managing. Most commonly, applications bill individual users for monthly and yearly subscription plans. However, your application may choose to bill some other type of model, such as a team, organization, band, etc.")]),a._v(" "),s("p",[a._v("You may define your billable models within the "),s("code",[a._v("billables")]),a._v(" array of your application's "),s("code",[a._v("spark")]),a._v(" configuration file. By default, this array contains an entry for the "),s("code",[a._v("App\\Models\\User")]),a._v(" model.")]),a._v(" "),s("p",[a._v("Before continuing, you should ensure that the model class that corresponds to your billable model is using the "),s("code",[a._v("Spark\\Billable")]),a._v(" trait:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[a._v("")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("p",[a._v("However, if your application is not billing individual users, you may need to adjust this callback. For example, if your application offers team billing instead of user billing, you might customize the callback like so:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("currentTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("h3",{attrs:{id:"billable-authorization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-authorization"}},[a._v("#")]),a._v(" Billable Authorization")]),a._v(" "),s("p",[a._v("Next, let's examine the authorization callbacks that Spark will use to determine if the currently authenticated user of your application is authorized to view the billing portal for a particular billable model.")]),a._v(" "),s("p",[a._v("When you installed Laravel Spark, an "),s("code",[a._v("App\\Providers\\SparkServiceProvider")]),a._v(" class was created for you. Within this service provider, you will find the authorization callback definition used to determine if a given user is authorized to view the billing portal for the "),s("code",[a._v("App\\Models\\User")]),a._v(" billable class. Of course, if your application is not billing users, you should update the billable class and authorization callback logic to fit your application's needs. By default, Spark will simply verify that the currently authenticated user can only manage its own billing settings:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("User")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&&")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("id")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("==")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("p",[a._v("If the authorization callback returns "),s("code",[a._v("true")]),a._v(", the currently authenticated user will be authorized to view the billing portal and manage the billing settings for the given "),s("code",[a._v("$billable")]),a._v(" model. If the callback returns "),s("code",[a._v("false")]),a._v(", the request to access the billing portal will be denied.")]),a._v(" "),s("p",[a._v("You are free to customize the "),s("code",[a._v("authorize")]),a._v(" callback based on your own application's needs. For example, if your application bills teams instead of individual users, you might update the callback like so:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Team")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&&")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("ownsTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("h3",{attrs:{id:"billable-email-address"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-email-address"}},[a._v("#")]),a._v(" Billable Email Address")]),a._v(" "),s("p",[a._v("By default, Spark will use your billable model's "),s("code",[a._v("email")]),a._v(" attribute as the email address associated with the Paddle customer record it creates for the model. If you would like to specify another attribute that should be used instead, you may define a "),s("code",[a._v("paddleEmail")]),a._v(" method on your billable model:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("/**\n * Get the email address that should be associated with the Paddle customer.\n *\n * @return string\n */")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("public")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[a._v("paddleEmail")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$this")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("email")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("h2",{attrs:{id:"defining-subscription-plans"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#defining-subscription-plans"}},[a._v("#")]),a._v(" Defining Subscription Plans")]),a._v(" "),s("p",[a._v("As we previously discussed, Spark allows you to define the types of billable models that your application will be managing. These billable models are defined within the "),s("code",[a._v("billables")]),a._v(" array of your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file:")]),a._v(" "),s("p",[a._v("Each billable configuration within the "),s("code",[a._v("billables")]),a._v(" array contains a "),s("code",[a._v("plans")]),a._v(" array. Within this array you may configure each of the billing plans offered by your application to that particular billable type. "),s("strong",[a._v("The "),s("code",[a._v("monthly_id")]),a._v(" and "),s("code",[a._v("yearly_id")]),a._v(" identifiers should correspond to the plan identifiers associated with the subscription plan within your Paddle account dashboard:")])]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'billables'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'user'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'model'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'trial_days'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'plans'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'name'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Standard'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'short_description'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'This is a short, human friendly description of the plan.'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'monthly_id'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("env")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'SPARK_STANDARD_MONTHLY_PLAN'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'yearly_id'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("env")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'SPARK_STANDARD_YEARLY_PLAN'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("1001")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'features'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Feature 1'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Feature 2'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Feature 3'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v("\n")])])]),s("p",[a._v("If your subscription plan only offers a monthly billing cycle, you may omit the "),s("code",[a._v("yearly_id")]),a._v(" identifier from your plan configuration. Likewise, if your plan only offers a yearly billing cycle, you may omit the "),s("code",[a._v("monthly_id")]),a._v(" identifier.")]),a._v(" "),s("p",[a._v("In addition, you are free to supply a short description of the plan and a list of features relevant to the plan. This information will be displayed in the Spark billing portal.")]),a._v(" "),s("h2",{attrs:{id:"accessing-the-billing-portal"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#accessing-the-billing-portal"}},[a._v("#")]),a._v(" Accessing The Billing Portal")]),a._v(" "),s("p",[a._v("Once you have configured your Spark installation, you may access your application's billing portal at the "),s("code",[a._v("/billing")]),a._v(" URI. So, if your application is being served on "),s("code",[a._v("localhost")]),a._v(", you may access your application's billing portal at "),s("code",[a._v("http://localhost/billing")]),a._v(".")]),a._v(" "),s("p",[a._v("Of course, you may link to the billing portal from your application's dashboard however you see fit:")]),a._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("a")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("href")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v('"')]),a._v("/billing"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("\n Manage Subscription\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n")])])]),s("h4",{attrs:{id:"billing-portal-multiple-billables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billing-portal-multiple-billables"}},[a._v("#")]),a._v(" Billing Portal & Multiple Billables")]),a._v(" "),s("p",[a._v("If your application is billing more than one type of billable, you should add the billable type's "),s("a",{attrs:{href:"#billable-slugs"}},[a._v("slug")]),a._v(" to the "),s("code",[a._v("/billing")]),a._v(" URI. For example, if you have configured a "),s("code",[a._v("team")]),a._v(" billable type in addition to your "),s("code",[a._v("user")]),a._v(" billable type, you may access the billing portal for teams by navigating to "),s("code",[a._v("http://localhost/billing/team")]),a._v(". However, this typically should not be necessary because most applications will only ever bill one type of model.")]),a._v(" "),s("h2",{attrs:{id:"showing-a-link-to-the-terms-and-conditions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[a._v("#")]),a._v(" Showing A Link To The Terms And Conditions")]),a._v(" "),s("p",[a._v("Many applications display billing terms and conditions during checkout. Spark allows you to easily do the same within your application's billing portal. To get started, add a "),s("code",[a._v("terms_url")]),a._v(" configuration value in your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'terms_url'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'/terms'")]),a._v("\n")])])]),s("p",[a._v("Once added, Spark will display a link pointing to "),s("code",[a._v("/terms")]),a._v(" in the billing portal.")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/16.edc3dc4f.js b/.vuepress/dist/assets/js/16.10ef0c2b.js similarity index 99% rename from .vuepress/dist/assets/js/16.edc3dc4f.js rename to .vuepress/dist/assets/js/16.10ef0c2b.js index 51b59ee..32c5257 100644 --- a/.vuepress/dist/assets/js/16.edc3dc4f.js +++ b/.vuepress/dist/assets/js/16.10ef0c2b.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{407:function(t,a,s){"use strict";s.r(a);var n=s(55),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"cookbook"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#cookbook"}},[t._v("#")]),t._v(" Cookbook")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#team-billing"}},[t._v("Team Billing")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"team-billing"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#team-billing"}},[t._v("#")]),t._v(" Team Billing")]),t._v(" "),s("p",[t._v('Spark ships with "user" based billing by default. If your applications bills teams or a different model instead, you will need to adjust your Spark installation accordingly. We\'ll walk through these adjustments in the following documentation using a team billing implementation as an example.')]),t._v(" "),s("p",[t._v("To make the "),s("code",[t._v("App\\Models\\Team")]),t._v(" model our billable model, we first need to adjust Spark's service provider.")]),t._v(" "),s("h4",{attrs:{id:"updating-the-service-provider"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-service-provider"}},[t._v("#")]),t._v(" Updating The Service Provider")]),t._v(" "),s("p",[t._v("Now we should update the "),s("code",[t._v("SparkServiceProvider")]),t._v(" to reference the "),s("code",[t._v("Team")]),t._v(" model instead of the "),s("code",[t._v("User")]),t._v(" model:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("SparkServiceProvider")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServiceProvider")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Bootstrap any application services.\n *\n * @return void\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("boot")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Resolve the current team...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("currentTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Verify that the current user owns the team...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("id")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("user_id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkPlanEligibility")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Plan")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h4",{attrs:{id:"updating-the-model"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-model"}},[t._v("#")]),t._v(" Updating The Model")]),t._v(" "),s("p",[t._v("Now we can update the "),s("code",[t._v("Team")]),t._v(" model to use the "),s("code",[t._v("Spark\\Billable")]),t._v(" trait and implement a "),s("code",[t._v("paddleEmail")]),t._v(" method that returns the team owner's email address to be displayed in the Paddle dashboard as the customer identifier:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JetstreamTeam")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("paddleEmail")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$this")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("owner")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("email")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h4",{attrs:{id:"spark-configuration-file"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#spark-configuration-file"}},[t._v("#")]),t._v(" Spark Configuration File")]),t._v(" "),s("p",[t._v("Finally, update your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file so that it defines a "),s("code",[t._v("team")]),t._v(" billable model:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'billables'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'team'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'model'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{410:function(t,a,s){"use strict";s.r(a);var n=s(55),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"cookbook"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#cookbook"}},[t._v("#")]),t._v(" Cookbook")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#team-billing"}},[t._v("Team Billing")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"team-billing"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#team-billing"}},[t._v("#")]),t._v(" Team Billing")]),t._v(" "),s("p",[t._v('Spark ships with "user" based billing by default. If your applications bills teams or a different model instead, you will need to adjust your Spark installation accordingly. We\'ll walk through these adjustments in the following documentation using a team billing implementation as an example.')]),t._v(" "),s("p",[t._v("To make the "),s("code",[t._v("App\\Models\\Team")]),t._v(" model our billable model, we first need to adjust Spark's service provider.")]),t._v(" "),s("h4",{attrs:{id:"updating-the-service-provider"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-service-provider"}},[t._v("#")]),t._v(" Updating The Service Provider")]),t._v(" "),s("p",[t._v("Now we should update the "),s("code",[t._v("SparkServiceProvider")]),t._v(" to reference the "),s("code",[t._v("Team")]),t._v(" model instead of the "),s("code",[t._v("User")]),t._v(" model:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("SparkServiceProvider")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServiceProvider")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Bootstrap any application services.\n *\n * @return void\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("boot")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Resolve the current team...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("currentTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Verify that the current user owns the team...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("id")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("user_id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkPlanEligibility")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Plan")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h4",{attrs:{id:"updating-the-model"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-model"}},[t._v("#")]),t._v(" Updating The Model")]),t._v(" "),s("p",[t._v("Now we can update the "),s("code",[t._v("Team")]),t._v(" model to use the "),s("code",[t._v("Spark\\Billable")]),t._v(" trait and implement a "),s("code",[t._v("paddleEmail")]),t._v(" method that returns the team owner's email address to be displayed in the Paddle dashboard as the customer identifier:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JetstreamTeam")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("paddleEmail")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$this")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("owner")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("email")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h4",{attrs:{id:"spark-configuration-file"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#spark-configuration-file"}},[t._v("#")]),t._v(" Spark Configuration File")]),t._v(" "),s("p",[t._v("Finally, update your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file so that it defines a "),s("code",[t._v("team")]),t._v(" billable model:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'billables'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'team'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'model'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/36.a14c3334.js b/.vuepress/dist/assets/js/17.f62f4989.js similarity index 99% rename from .vuepress/dist/assets/js/36.a14c3334.js rename to .vuepress/dist/assets/js/17.f62f4989.js index 0a094a5..3c6bbe9 100644 --- a/.vuepress/dist/assets/js/36.a14c3334.js +++ b/.vuepress/dist/assets/js/17.f62f4989.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[36],{433:function(t,a,s){"use strict";s.r(a);var e=s(55),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"customization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#customization"}},[t._v("#")]),t._v(" Customization")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#branding"}},[t._v("Branding")]),s("ul",[s("li",[s("a",{attrs:{href:"#brand-logo"}},[t._v("Brand Logo")])]),s("li",[s("a",{attrs:{href:"#brand-color"}},[t._v("Brand Color")])]),s("li",[s("a",{attrs:{href:"#font"}},[t._v("Font")])])])]),s("li",[s("a",{attrs:{href:"#localization"}},[t._v("Localization")])]),s("li",[s("a",{attrs:{href:"#webhooks"}},[t._v("Webhooks")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"branding"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#branding"}},[t._v("#")]),t._v(" Branding")]),t._v(" "),s("p",[t._v("Although Spark's billing portal is intended to be an isolated part of your application that is entirely managed by Spark, you can make some small customizations to the branding logo and color used by Spark.")]),t._v(" "),s("h3",{attrs:{id:"brand-logo"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#brand-logo"}},[t._v("#")]),t._v(" Brand Logo")]),t._v(" "),s("p",[t._v("To customize the logo used at the top left of the Spark billing portal, you may specify a configuration value for the "),s("code",[t._v("brand.logo")]),t._v(" configuration item within your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file. This configuration value should contain an absolute path to the SVG file of the logo you would like to use:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'brand'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'logo'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("realpath")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("__DIR__")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/../public/img/logo.svg'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("SVG Sizing")]),t._v(" "),s("p",[t._v("You may need to adjust the size and width of your SVG logo by modifying its width in the SVG file itself.")])]),t._v(" "),s("h3",{attrs:{id:"brand-color"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#brand-color"}},[t._v("#")]),t._v(" Brand Color")]),t._v(" "),s("p",[t._v("To customize the color used as the background color of the button elements within the Spark billing portal, you may specify a value for the "),s("code",[t._v("brand.color")]),t._v(" configuration item within your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file. This configuration value should be a valid hex code or correspond to a background color offered by the "),s("a",{attrs:{href:"https://tailwindcss.com/docs/customizing-colors",target:"_blank",rel:"noopener noreferrer"}},[t._v("Tailwind CSS framework"),s("OutboundLink")],1),t._v(":")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'brand'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'bg-indigo-600'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Or...")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'#c5b358'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("h3",{attrs:{id:"font"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#font"}},[t._v("#")]),t._v(" Font")]),t._v(" "),s("p",[t._v("To customize the font used by the Spark billing portal, you should export Spark's views using the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-views\n")])])]),s("p",[t._v("Next, within the "),s("code",[t._v("resources/views/vendor/spark/app.blade.php")]),t._v(" template, you may define your own "),s("code",[t._v("font-sans")]),t._v(" CSS class at the bottom of the templates "),s("code",[t._v("head")]),t._v(" section:")]),t._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("head")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("\x3c!-- ...... --\x3e")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("style")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token style"}},[s("span",{pre:!0,attrs:{class:"token language-css"}},[t._v("\n "),s("span",{pre:!0,attrs:{class:"token selector"}},[t._v(".font-sans")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("font-family")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Your Custom Font'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n ")])]),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("h2",{attrs:{id:"localization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#localization"}},[t._v("#")]),t._v(" Localization")]),t._v(" "),s("p",[t._v("You may localize / translate all of the text within the Spark billing portal. To publish the Spark localization file, you may use the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-lang\n")])])]),s("p",[t._v("This command will publish a "),s("code",[t._v("resources/lang/spark/en.json")]),t._v(" file containing translation keys and values for the English language. You may copy this file and translate it to the language of your choice. For more information on how to use Laravel's translation features, please consult the "),s("a",{attrs:{href:"https://laravel.com/docs/localization#using-translation-strings-as-keys",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel localization documentation"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks"}},[t._v("#")]),t._v(" Webhooks")]),t._v(" "),s("p",[t._v("Spark and Cashier automatically handles subscription cancellation on failed charges and other common Paddle webhooks, but if you have additional webhook events you would like to handle, you should extend Spark's "),s("code",[t._v("WebhookController")]),t._v(".")]),t._v(" "),s("p",[t._v("Your controller's method names should correspond to Cashier's controller method conventions. Specifically, methods should be prefixed with "),s("code",[t._v("handle")]),t._v(' and the "camel case" name of the webhook you wish to handle. For example, if you wish to handle the '),s("code",[t._v("payment_succeeded")]),t._v(" webhook, you should add a "),s("code",[t._v("handlePaymentSucceeded")]),t._v(" method to the controller:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[t._v("")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'logo'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("realpath")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("__DIR__")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/../public/img/logo.svg'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("SVG Sizing")]),t._v(" "),s("p",[t._v("You may need to adjust the size and width of your SVG logo by modifying its width in the SVG file itself.")])]),t._v(" "),s("h3",{attrs:{id:"brand-color"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#brand-color"}},[t._v("#")]),t._v(" Brand Color")]),t._v(" "),s("p",[t._v("To customize the color used as the background color of the button elements within the Spark billing portal, you may specify a value for the "),s("code",[t._v("brand.color")]),t._v(" configuration item within your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file. This configuration value should be a valid hex code or correspond to a background color offered by the "),s("a",{attrs:{href:"https://tailwindcss.com/docs/customizing-colors",target:"_blank",rel:"noopener noreferrer"}},[t._v("Tailwind CSS framework"),s("OutboundLink")],1),t._v(":")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'brand'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'bg-indigo-600'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Or...")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'#c5b358'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("h3",{attrs:{id:"font"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#font"}},[t._v("#")]),t._v(" Font")]),t._v(" "),s("p",[t._v("To customize the font used by the Spark billing portal, you should export Spark's views using the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-views\n")])])]),s("p",[t._v("Next, within the "),s("code",[t._v("resources/views/vendor/spark/app.blade.php")]),t._v(" template, you may define your own "),s("code",[t._v("font-sans")]),t._v(" CSS class at the bottom of the templates "),s("code",[t._v("head")]),t._v(" section:")]),t._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("head")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("\x3c!-- ...... --\x3e")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("style")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token style"}},[s("span",{pre:!0,attrs:{class:"token language-css"}},[t._v("\n "),s("span",{pre:!0,attrs:{class:"token selector"}},[t._v(".font-sans")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("font-family")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Your Custom Font'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n ")])]),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("h2",{attrs:{id:"localization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#localization"}},[t._v("#")]),t._v(" Localization")]),t._v(" "),s("p",[t._v("You may localize / translate all of the text within the Spark billing portal. To publish the Spark localization file, you may use the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-lang\n")])])]),s("p",[t._v("This command will publish a "),s("code",[t._v("resources/lang/spark/en.json")]),t._v(" file containing translation keys and values for the English language. You may copy this file and translate it to the language of your choice. For more information on how to use Laravel's translation features, please consult the "),s("a",{attrs:{href:"https://laravel.com/docs/localization#using-translation-strings-as-keys",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel localization documentation"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks"}},[t._v("#")]),t._v(" Webhooks")]),t._v(" "),s("p",[t._v("Spark and Cashier automatically handles subscription cancellation on failed charges and other common Paddle webhooks, but if you have additional webhook events you would like to handle, you should extend Spark's "),s("code",[t._v("WebhookController")]),t._v(".")]),t._v(" "),s("p",[t._v("Your controller's method names should correspond to Cashier's controller method conventions. Specifically, methods should be prefixed with "),s("code",[t._v("handle")]),t._v(' and the "camel case" name of the webhook you wish to handle. For example, if you wish to handle the '),s("code",[t._v("payment_succeeded")]),t._v(" webhook, you should add a "),s("code",[t._v("handlePaymentSucceeded")]),t._v(" method to the controller:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[t._v("")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("VerifyBillableIsSubscribed")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Once the middleware has been registered, you may attach it to any of your application's route definitions:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Route")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("post")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/projects'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ProjectController")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'store'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("middleware")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'auth'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("If the user has an active subscription, the request will continue to execute normally. However, if the user does not have an active subscription, they will be redirected to your application's Spark billing portal. If the request is an XHR request, a response with a 402 HTTP status code will be returned to the client.")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("Manually Inspecting Subscription States")]),t._v(" "),a("p",[t._v("Of course, you may always manually inspect a billable model's subscription status using the "),a("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),a("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan.")])]),t._v(" "),a("h4",{attrs:{id:"multiple-billables"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#multiple-billables"}},[t._v("#")]),t._v(" Multiple Billables")]),t._v(" "),a("p",[t._v("If your application has more than one configured billable model, you may pass the "),a("RouterLink",{attrs:{to:"/1.x/spark-paddle/configuration.html#billable-slugs"}},[t._v("billable slug")]),t._v(" to the middleware to instruct Spark which billable model configuration to use when verifying the subscription. However, this typically should not be necessary because most applications will only ever bill one type of model:")],1),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Route")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("post")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/projects'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ProjectController")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'store'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("middleware")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'auth'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed:team'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{413:function(t,s,a){"use strict";a.r(s);var e=a(55),n=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"middleware"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#middleware"}},[t._v("#")]),t._v(" Middleware")]),t._v(" "),a("p"),a("div",{staticClass:"table-of-contents"},[a("ul")]),a("p"),t._v(" "),a("p",[t._v("When building a subscription based application, you will commonly need to restrict access to certain routes to users that have an active subscription. For example, you may not want to let a user create a project if they are not subscribed to a billing plan. For that reason, Spark provides a convenient subscription verification "),a("a",{attrs:{href:"https://laravel.com/docs/middleware",target:"_blank",rel:"noopener noreferrer"}},[t._v("middleware"),a("OutboundLink")],1),t._v(" that you may register with your application.")]),t._v(" "),a("p",[t._v("To get started, register Spark's subscription verification middleware in your HTTP kernel's "),a("code",[t._v("$routeMiddleware")]),t._v(" array. Your application's HTTP kernel is typically located at "),a("code",[t._v("app/Http/Kernel.php")]),t._v(":")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Middleware"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("VerifyBillableIsSubscribed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("protected")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$routeMiddleware")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("VerifyBillableIsSubscribed")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Once the middleware has been registered, you may attach it to any of your application's route definitions:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Route")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("post")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/projects'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ProjectController")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'store'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("middleware")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'auth'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("If the user has an active subscription, the request will continue to execute normally. However, if the user does not have an active subscription, they will be redirected to your application's Spark billing portal. If the request is an XHR request, a response with a 402 HTTP status code will be returned to the client.")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("Manually Inspecting Subscription States")]),t._v(" "),a("p",[t._v("Of course, you may always manually inspect a billable model's subscription status using the "),a("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),a("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan.")])]),t._v(" "),a("h4",{attrs:{id:"multiple-billables"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#multiple-billables"}},[t._v("#")]),t._v(" Multiple Billables")]),t._v(" "),a("p",[t._v("If your application has more than one configured billable model, you may pass the "),a("RouterLink",{attrs:{to:"/1.x/spark-paddle/configuration.html#billable-slugs"}},[t._v("billable slug")]),t._v(" to the middleware to instruct Spark which billable model configuration to use when verifying the subscription. However, this typically should not be necessary because most applications will only ever bill one type of model:")],1),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Route")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("post")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/projects'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ProjectController")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'store'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("middleware")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'auth'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed:team'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/39.cf57a51d.js b/.vuepress/dist/assets/js/20.ae0c3f38.js similarity index 99% rename from .vuepress/dist/assets/js/39.cf57a51d.js rename to .vuepress/dist/assets/js/20.ae0c3f38.js index 937199c..de058f0 100644 --- a/.vuepress/dist/assets/js/39.cf57a51d.js +++ b/.vuepress/dist/assets/js/20.ae0c3f38.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[39],{436:function(t,s,a){"use strict";a.r(s);var n=a(55),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"testing"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#testing"}},[t._v("#")]),t._v(" Testing")]),t._v(" "),a("p"),a("div",{staticClass:"table-of-contents"},[a("ul",[a("li",[a("a",{attrs:{href:"#factories"}},[t._v("Factories")])])])]),a("p"),t._v(" "),a("h2",{attrs:{id:"factories"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#factories"}},[t._v("#")]),t._v(" Factories")]),t._v(" "),a("p",[t._v('While developing your application, you will likely want to "stub" a subscription record in your application\'s database so that calls to the '),a("code",[t._v("$billable->subscribed()")]),t._v(" method return "),a("code",[t._v("true")]),t._v(".")]),t._v(" "),a("p",[t._v('To accomplish this, you may add a "state" method to your billable model\'s '),a("a",{attrs:{href:"https://laravel.com/docs/database-testing#defining-model-factories",target:"_blank",rel:"noopener noreferrer"}},[t._v("factory class"),a("OutboundLink")],1),t._v(". Typically, this will be your application's "),a("code",[t._v("UserFactory")]),t._v(" class. Below you will find an example state method implementation; however, you are free to adjust this to your application's own needs:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Indicate that the user should have a subscription plan.\n *\n * @param int $planId\n * @return \\Illuminate\\Database\\Eloquent\\Factories\\Factory\n */")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$this")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("afterCreating")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("optional")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token property"}},[t._v("customer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("update")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscriptions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'default'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paddle_id'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("random_int")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paddle_status'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'active'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paddle_plan'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'quantity'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paused_from'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Once you have define the state method, you may use it when creating models via your factory:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("factory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// true")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{415:function(t,s,a){"use strict";a.r(s);var n=a(55),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"testing"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#testing"}},[t._v("#")]),t._v(" Testing")]),t._v(" "),a("p"),a("div",{staticClass:"table-of-contents"},[a("ul",[a("li",[a("a",{attrs:{href:"#factories"}},[t._v("Factories")])])])]),a("p"),t._v(" "),a("h2",{attrs:{id:"factories"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#factories"}},[t._v("#")]),t._v(" Factories")]),t._v(" "),a("p",[t._v('While developing your application, you will likely want to "stub" a subscription record in your application\'s database so that calls to the '),a("code",[t._v("$billable->subscribed()")]),t._v(" method return "),a("code",[t._v("true")]),t._v(".")]),t._v(" "),a("p",[t._v('To accomplish this, you may add a "state" method to your billable model\'s '),a("a",{attrs:{href:"https://laravel.com/docs/database-testing#defining-model-factories",target:"_blank",rel:"noopener noreferrer"}},[t._v("factory class"),a("OutboundLink")],1),t._v(". Typically, this will be your application's "),a("code",[t._v("UserFactory")]),t._v(" class. Below you will find an example state method implementation; however, you are free to adjust this to your application's own needs:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Indicate that the user should have a subscription plan.\n *\n * @param int $planId\n * @return \\Illuminate\\Database\\Eloquent\\Factories\\Factory\n */")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$this")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("afterCreating")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("optional")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token property"}},[t._v("customer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("update")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscriptions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'default'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paddle_id'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("random_int")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paddle_status'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'active'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paddle_plan'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'quantity'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paused_from'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Once you have define the state method, you may use it when creating models via your factory:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("factory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// true")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/21.bce379e0.js b/.vuepress/dist/assets/js/21.fad78231.js similarity index 84% rename from .vuepress/dist/assets/js/21.bce379e0.js rename to .vuepress/dist/assets/js/21.fad78231.js index b07f50f..f558997 100644 --- a/.vuepress/dist/assets/js/21.bce379e0.js +++ b/.vuepress/dist/assets/js/21.fad78231.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{415:function(t,e,n){"use strict";n.r(e);var s=n(55),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("meta",{attrs:{"http-equiv":"refresh",content:"0;url=/docs/1.x/spark-paddle/configuration.html"}})])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{416:function(t,e,n){"use strict";n.r(e);var s=n(55),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("meta",{attrs:{"http-equiv":"refresh",content:"0;url=/docs/1.x/spark-paddle/configuration.html"}})])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/42.002a01e2.js b/.vuepress/dist/assets/js/22.3214753d.js similarity index 99% rename from .vuepress/dist/assets/js/42.002a01e2.js rename to .vuepress/dist/assets/js/22.3214753d.js index 626c30f..718fd9f 100644 --- a/.vuepress/dist/assets/js/42.002a01e2.js +++ b/.vuepress/dist/assets/js/22.3214753d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[42],{437:function(t,a,s){"use strict";s.r(a);var e=s(55),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuration"}},[t._v("#")]),t._v(" Configuration")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#introduction"}},[t._v("Introduction")])]),s("li",[s("a",{attrs:{href:"#stripe-configuration"}},[t._v("Stripe Configuration")]),s("ul",[s("li",[s("a",{attrs:{href:"#environment-variables"}},[t._v("Environment Variables")])]),s("li",[s("a",{attrs:{href:"#stripe-webhooks"}},[t._v("Stripe Webhooks")])])])]),s("li",[s("a",{attrs:{href:"#configuring-billables"}},[t._v("Configuring Billables")]),s("ul",[s("li",[s("a",{attrs:{href:"#billable-slugs"}},[t._v("Billable Slugs")])]),s("li",[s("a",{attrs:{href:"#billable-resolution"}},[t._v("Billable Resolution")])]),s("li",[s("a",{attrs:{href:"#billable-authorization"}},[t._v("Billable Authorization")])])])]),s("li",[s("a",{attrs:{href:"#defining-subscription-plans"}},[t._v("Defining Subscription Plans")])]),s("li",[s("a",{attrs:{href:"#accessing-the-billing-portal"}},[t._v("Accessing The Billing Portal")])]),s("li",[s("a",{attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[t._v("Showing A Link To The Terms And Conditions")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"introduction"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),s("p",[t._v("In the following documentation, we will discuss how to configure a Laravel Spark installation when using the "),s("a",{attrs:{href:"https://stripe.com",target:"_blank",rel:"noopener noreferrer"}},[t._v("Stripe"),s("OutboundLink")],1),t._v(" payment provider. All of Spark's configuration options are housed in your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file.")]),t._v(" "),s("h2",{attrs:{id:"stripe-configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#stripe-configuration"}},[t._v("#")]),t._v(" Stripe Configuration")]),t._v(" "),s("p",[t._v("Of course, to use Stripe as a payment provider for your Laravel Spark application you must have an active "),s("a",{attrs:{href:"https://stripe.com",target:"_blank",rel:"noopener noreferrer"}},[t._v("Stripe account"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"environment-variables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#environment-variables"}},[t._v("#")]),t._v(" Environment Variables")]),t._v(" "),s("p",[t._v("Next, you should configure the application environment variables that will be needed by Spark in order to access your Stripe account. These variables should be placed in your application's "),s("code",[t._v(".env")]),t._v(" environment file.")]),t._v(" "),s("p",[t._v("Of course, you should adjust the variable's values to correspond to your own Stripe account's credentials. Your Stripe API credentials and public key are available in your Stripe account dashboard:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("CASHIER_CURRENCY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("USD\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("CASHIER_CURRENCY_LOCALE")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("en\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("STRIPE_KEY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("pk_test_example\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("STRIPE_SECRET")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("sk_test_example\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("STRIPE_WEBHOOK_SECRET")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("sk_test_example\n")])])]),s("div",{staticClass:"custom-block danger"},[s("p",{staticClass:"custom-block-title"},[t._v("Configuring Locales")]),t._v(" "),s("p",[t._v("In order to use locales other than "),s("code",[t._v("en")]),t._v(", ensure the "),s("code",[t._v("ext-intl")]),t._v(" PHP extension is installed and configured on your server.")])]),t._v(" "),s("h3",{attrs:{id:"stripe-webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#stripe-webhooks"}},[t._v("#")]),t._v(" Stripe Webhooks")]),t._v(" "),s("p",[t._v("In addition, your Spark powered application will need to receive webhooks from Stripe in order to keep your application's billing and subscription data in sync with Stripe's. Within your Stripe dashboard's webhook management panel, you should configure Stripe to send webhook alerts to your application's "),s("code",[t._v("/spark/webhook")]),t._v(" URI. You should enable webhook alerts for the following events:")]),t._v(" "),s("ul",[s("li",[t._v("customer.deleted")]),t._v(" "),s("li",[t._v("customer.subscription.created")]),t._v(" "),s("li",[t._v("customer.subscription.deleted")]),t._v(" "),s("li",[t._v("customer.subscription.updated")]),t._v(" "),s("li",[t._v("customer.updated")]),t._v(" "),s("li",[t._v("invoice.payment_action_required")]),t._v(" "),s("li",[t._v("invoice.payment_succeeded")])]),t._v(" "),s("h4",{attrs:{id:"webhooks-local-development"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks-local-development"}},[t._v("#")]),t._v(" Webhooks & Local Development")]),t._v(" "),s("p",[t._v("For Stripe to be able to send your application webhooks during local development, you will need to expose your application via a site sharing service such as "),s("a",{attrs:{href:"https://ngrok.io",target:"_blank",rel:"noopener noreferrer"}},[t._v("Ngrok"),s("OutboundLink")],1),t._v(" or "),s("a",{attrs:{href:"https://beyondco.de/docs/expose/introduction",target:"_blank",rel:"noopener noreferrer"}},[t._v("Expose"),s("OutboundLink")],1),t._v(". If you are developing your application locally using "),s("a",{attrs:{href:"http://laravel.com/docs/sail",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel Sail"),s("OutboundLink")],1),t._v(", you may use Sail's "),s("a",{attrs:{href:"https://laravel.com/docs/sail#sharing-your-site",target:"_blank",rel:"noopener noreferrer"}},[t._v("site sharing command"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"configuring-billables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuring-billables"}},[t._v("#")]),t._v(" Configuring Billables")]),t._v(" "),s("p",[t._v("Spark allows you to define the types of billable models that your application will be managing. Most commonly, applications bill individual users for monthly and yearly subscription plans. However, your application may choose to bill some other type of model, such as a team, organization, band, etc.")]),t._v(" "),s("p",[t._v("You may define your billable models within the "),s("code",[t._v("billables")]),t._v(" array of your application's "),s("code",[t._v("spark")]),t._v(" configuration file. By default, this array contains an entry for the "),s("code",[t._v("App\\Models\\User")]),t._v(" model.")]),t._v(" "),s("p",[t._v("Before continuing, you should ensure that the model class that corresponds to your billable model is using the "),s("code",[t._v("Spark\\Billable")]),t._v(" trait and that it casts the "),s("code",[t._v("trial_ends_at")]),t._v(" attribute to "),s("code",[t._v("datetime")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[t._v("")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'datetime'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]),s("h3",{attrs:{id:"billable-slugs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-slugs"}},[t._v("#")]),t._v(" Billable Slugs")]),t._v(" "),s("p",[t._v("As you may have noticed, each entry in the "),s("code",[t._v("billables")]),t._v(' configuration array is keyed by a "slug" that is a shortened form of the billable model class. This slug can be used when accessing the Spark customer billing portal, such as '),s("code",[t._v("https://example.com/billing/user")]),t._v(" or "),s("code",[t._v("https://example.com/billing/team")]),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"billable-resolution"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-resolution"}},[t._v("#")]),t._v(" Billable Resolution")]),t._v(" "),s("p",[t._v("When you installed Laravel Spark, an "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class was created for you. Within this service provider, you will find a callback that is used by Spark to resolve the billable model instance when accessing the Spark billing portal. By default, this callback simply returns the currently authenticated user, which is the desired behavior for most applications using Laravel Spark:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("However, if your application is not billing individual users, you may need to adjust this callback. For example, if your application offers team billing instead of user billing, you might customize the callback like so:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("currentTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("h3",{attrs:{id:"billable-authorization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-authorization"}},[t._v("#")]),t._v(" Billable Authorization")]),t._v(" "),s("p",[t._v("Next, let's examine the authorization callbacks that Spark will use to determine if the currently authenticated user of your application is authorized to view the billing portal for a particular billable model.")]),t._v(" "),s("p",[t._v("When you installed Laravel Spark, an "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class was created for you. Within this service provider, you will find the authorization callback definition used to determine if a given user is authorized to view the billing portal for the "),s("code",[t._v("App\\Models\\User")]),t._v(" billable class. Of course, if your application is not billing users, you should update the billable class and authorization callback logic to fit your application's needs. By default, Spark will simply verify that the currently authenticated user can only manage its own billing settings:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("User")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("id")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("If the authorization callback returns "),s("code",[t._v("true")]),t._v(", the currently authenticated user will be authorized to view the billing portal and manage the billing settings for the given "),s("code",[t._v("$billable")]),t._v(" model. If the callback returns "),s("code",[t._v("false")]),t._v(", the request to access the billing portal will be denied.")]),t._v(" "),s("p",[t._v("You are free to customize the "),s("code",[t._v("authorize")]),t._v(" callback based on your own application's needs. For example, if your application bills teams instead of individual users, you might update the callback like so:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ownsTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("h2",{attrs:{id:"defining-subscription-plans"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#defining-subscription-plans"}},[t._v("#")]),t._v(" Defining Subscription Plans")]),t._v(" "),s("p",[t._v("As we previously discussed, Spark allows you to define the types of billable models that your application will be managing. These billable models are defined within the "),s("code",[t._v("billables")]),t._v(" array of your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),s("p",[t._v("Each billable configuration within the "),s("code",[t._v("billables")]),t._v(" array contains a "),s("code",[t._v("plans")]),t._v(" array. Within this array you may configure each of the billing plans offered by your application to that particular billable type. "),s("strong",[t._v("The "),s("code",[t._v("monthly_id")]),t._v(" and "),s("code",[t._v("yearly_id")]),t._v(" identifiers should correspond to the price / plan identifiers configured within your Stripe account dashboard:")])]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'billables'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'user'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'model'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_days'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 1'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 2'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 3'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("p",[t._v("If your subscription plan only offers a monthly billing cycle, you may omit the "),s("code",[t._v("yearly_id")]),t._v(" identifier from your plan configuration. Likewise, if your plan only offers a yearly billing cycle, you may omit the "),s("code",[t._v("monthly_id")]),t._v(" identifier.")]),t._v(" "),s("p",[t._v("In addition, you are free to supply a short description of the plan and a list of features relevant to the plan. This information will be displayed in the Spark billing portal.")]),t._v(" "),s("h2",{attrs:{id:"accessing-the-billing-portal"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#accessing-the-billing-portal"}},[t._v("#")]),t._v(" Accessing The Billing Portal")]),t._v(" "),s("p",[t._v("Once you have configured your Spark installation, you may access your application's billing portal at the "),s("code",[t._v("/billing")]),t._v(" URI. So, if your application is being served on "),s("code",[t._v("localhost")]),t._v(", you may access your application's billing portal at "),s("code",[t._v("http://localhost/billing")]),t._v(".")]),t._v(" "),s("p",[t._v("Of course, you may link to the billing portal from your application's dashboard however you see fit:")]),t._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("href")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("/billing"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n Manage Subscription\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("h2",{attrs:{id:"showing-a-link-to-the-terms-and-conditions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[t._v("#")]),t._v(" Showing A Link To The Terms And Conditions")]),t._v(" "),s("p",[t._v("Many applications display billing terms and conditions during checkout. Spark allows you to easily do the same within your application's billing portal. To get started, add a "),s("code",[t._v("terms_url")]),t._v(" configuration value in your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'terms_url'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/terms'")]),t._v("\n")])])]),s("p",[t._v("Once added, Spark will display a link pointing to "),s("code",[t._v("/terms")]),t._v(" in the billing portal.")])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{417:function(t,a,s){"use strict";s.r(a);var e=s(55),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuration"}},[t._v("#")]),t._v(" Configuration")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#introduction"}},[t._v("Introduction")])]),s("li",[s("a",{attrs:{href:"#stripe-configuration"}},[t._v("Stripe Configuration")]),s("ul",[s("li",[s("a",{attrs:{href:"#environment-variables"}},[t._v("Environment Variables")])]),s("li",[s("a",{attrs:{href:"#stripe-webhooks"}},[t._v("Stripe Webhooks")])])])]),s("li",[s("a",{attrs:{href:"#configuring-billables"}},[t._v("Configuring Billables")]),s("ul",[s("li",[s("a",{attrs:{href:"#billable-slugs"}},[t._v("Billable Slugs")])]),s("li",[s("a",{attrs:{href:"#billable-resolution"}},[t._v("Billable Resolution")])]),s("li",[s("a",{attrs:{href:"#billable-authorization"}},[t._v("Billable Authorization")])])])]),s("li",[s("a",{attrs:{href:"#defining-subscription-plans"}},[t._v("Defining Subscription Plans")])]),s("li",[s("a",{attrs:{href:"#accessing-the-billing-portal"}},[t._v("Accessing The Billing Portal")])]),s("li",[s("a",{attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[t._v("Showing A Link To The Terms And Conditions")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"introduction"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),s("p",[t._v("In the following documentation, we will discuss how to configure a Laravel Spark installation when using the "),s("a",{attrs:{href:"https://stripe.com",target:"_blank",rel:"noopener noreferrer"}},[t._v("Stripe"),s("OutboundLink")],1),t._v(" payment provider. All of Spark's configuration options are housed in your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file.")]),t._v(" "),s("h2",{attrs:{id:"stripe-configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#stripe-configuration"}},[t._v("#")]),t._v(" Stripe Configuration")]),t._v(" "),s("p",[t._v("Of course, to use Stripe as a payment provider for your Laravel Spark application you must have an active "),s("a",{attrs:{href:"https://stripe.com",target:"_blank",rel:"noopener noreferrer"}},[t._v("Stripe account"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"environment-variables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#environment-variables"}},[t._v("#")]),t._v(" Environment Variables")]),t._v(" "),s("p",[t._v("Next, you should configure the application environment variables that will be needed by Spark in order to access your Stripe account. These variables should be placed in your application's "),s("code",[t._v(".env")]),t._v(" environment file.")]),t._v(" "),s("p",[t._v("Of course, you should adjust the variable's values to correspond to your own Stripe account's credentials. Your Stripe API credentials and public key are available in your Stripe account dashboard:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("CASHIER_CURRENCY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("USD\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("CASHIER_CURRENCY_LOCALE")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("en\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("STRIPE_KEY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("pk_test_example\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("STRIPE_SECRET")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("sk_test_example\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("STRIPE_WEBHOOK_SECRET")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("sk_test_example\n")])])]),s("div",{staticClass:"custom-block danger"},[s("p",{staticClass:"custom-block-title"},[t._v("Configuring Locales")]),t._v(" "),s("p",[t._v("In order to use locales other than "),s("code",[t._v("en")]),t._v(", ensure the "),s("code",[t._v("ext-intl")]),t._v(" PHP extension is installed and configured on your server.")])]),t._v(" "),s("h3",{attrs:{id:"stripe-webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#stripe-webhooks"}},[t._v("#")]),t._v(" Stripe Webhooks")]),t._v(" "),s("p",[t._v("In addition, your Spark powered application will need to receive webhooks from Stripe in order to keep your application's billing and subscription data in sync with Stripe's. Within your Stripe dashboard's webhook management panel, you should configure Stripe to send webhook alerts to your application's "),s("code",[t._v("/spark/webhook")]),t._v(" URI. You should enable webhook alerts for the following events:")]),t._v(" "),s("ul",[s("li",[t._v("customer.deleted")]),t._v(" "),s("li",[t._v("customer.subscription.created")]),t._v(" "),s("li",[t._v("customer.subscription.deleted")]),t._v(" "),s("li",[t._v("customer.subscription.updated")]),t._v(" "),s("li",[t._v("customer.updated")]),t._v(" "),s("li",[t._v("invoice.payment_action_required")]),t._v(" "),s("li",[t._v("invoice.payment_succeeded")])]),t._v(" "),s("h4",{attrs:{id:"webhooks-local-development"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks-local-development"}},[t._v("#")]),t._v(" Webhooks & Local Development")]),t._v(" "),s("p",[t._v("For Stripe to be able to send your application webhooks during local development, you will need to expose your application via a site sharing service such as "),s("a",{attrs:{href:"https://ngrok.io",target:"_blank",rel:"noopener noreferrer"}},[t._v("Ngrok"),s("OutboundLink")],1),t._v(" or "),s("a",{attrs:{href:"https://beyondco.de/docs/expose/introduction",target:"_blank",rel:"noopener noreferrer"}},[t._v("Expose"),s("OutboundLink")],1),t._v(". If you are developing your application locally using "),s("a",{attrs:{href:"http://laravel.com/docs/sail",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel Sail"),s("OutboundLink")],1),t._v(", you may use Sail's "),s("a",{attrs:{href:"https://laravel.com/docs/sail#sharing-your-site",target:"_blank",rel:"noopener noreferrer"}},[t._v("site sharing command"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"configuring-billables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuring-billables"}},[t._v("#")]),t._v(" Configuring Billables")]),t._v(" "),s("p",[t._v("Spark allows you to define the types of billable models that your application will be managing. Most commonly, applications bill individual users for monthly and yearly subscription plans. However, your application may choose to bill some other type of model, such as a team, organization, band, etc.")]),t._v(" "),s("p",[t._v("You may define your billable models within the "),s("code",[t._v("billables")]),t._v(" array of your application's "),s("code",[t._v("spark")]),t._v(" configuration file. By default, this array contains an entry for the "),s("code",[t._v("App\\Models\\User")]),t._v(" model.")]),t._v(" "),s("p",[t._v("Before continuing, you should ensure that the model class that corresponds to your billable model is using the "),s("code",[t._v("Spark\\Billable")]),t._v(" trait and that it casts the "),s("code",[t._v("trial_ends_at")]),t._v(" attribute to "),s("code",[t._v("datetime")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[t._v("")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'datetime'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]),s("h3",{attrs:{id:"billable-slugs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-slugs"}},[t._v("#")]),t._v(" Billable Slugs")]),t._v(" "),s("p",[t._v("As you may have noticed, each entry in the "),s("code",[t._v("billables")]),t._v(' configuration array is keyed by a "slug" that is a shortened form of the billable model class. This slug can be used when accessing the Spark customer billing portal, such as '),s("code",[t._v("https://example.com/billing/user")]),t._v(" or "),s("code",[t._v("https://example.com/billing/team")]),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"billable-resolution"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-resolution"}},[t._v("#")]),t._v(" Billable Resolution")]),t._v(" "),s("p",[t._v("When you installed Laravel Spark, an "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class was created for you. Within this service provider, you will find a callback that is used by Spark to resolve the billable model instance when accessing the Spark billing portal. By default, this callback simply returns the currently authenticated user, which is the desired behavior for most applications using Laravel Spark:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("However, if your application is not billing individual users, you may need to adjust this callback. For example, if your application offers team billing instead of user billing, you might customize the callback like so:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("currentTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("h3",{attrs:{id:"billable-authorization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-authorization"}},[t._v("#")]),t._v(" Billable Authorization")]),t._v(" "),s("p",[t._v("Next, let's examine the authorization callbacks that Spark will use to determine if the currently authenticated user of your application is authorized to view the billing portal for a particular billable model.")]),t._v(" "),s("p",[t._v("When you installed Laravel Spark, an "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class was created for you. Within this service provider, you will find the authorization callback definition used to determine if a given user is authorized to view the billing portal for the "),s("code",[t._v("App\\Models\\User")]),t._v(" billable class. Of course, if your application is not billing users, you should update the billable class and authorization callback logic to fit your application's needs. By default, Spark will simply verify that the currently authenticated user can only manage its own billing settings:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("User")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("id")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("If the authorization callback returns "),s("code",[t._v("true")]),t._v(", the currently authenticated user will be authorized to view the billing portal and manage the billing settings for the given "),s("code",[t._v("$billable")]),t._v(" model. If the callback returns "),s("code",[t._v("false")]),t._v(", the request to access the billing portal will be denied.")]),t._v(" "),s("p",[t._v("You are free to customize the "),s("code",[t._v("authorize")]),t._v(" callback based on your own application's needs. For example, if your application bills teams instead of individual users, you might update the callback like so:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ownsTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("h2",{attrs:{id:"defining-subscription-plans"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#defining-subscription-plans"}},[t._v("#")]),t._v(" Defining Subscription Plans")]),t._v(" "),s("p",[t._v("As we previously discussed, Spark allows you to define the types of billable models that your application will be managing. These billable models are defined within the "),s("code",[t._v("billables")]),t._v(" array of your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),s("p",[t._v("Each billable configuration within the "),s("code",[t._v("billables")]),t._v(" array contains a "),s("code",[t._v("plans")]),t._v(" array. Within this array you may configure each of the billing plans offered by your application to that particular billable type. "),s("strong",[t._v("The "),s("code",[t._v("monthly_id")]),t._v(" and "),s("code",[t._v("yearly_id")]),t._v(" identifiers should correspond to the price / plan identifiers configured within your Stripe account dashboard:")])]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'billables'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'user'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'model'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_days'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 1'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 2'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 3'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("p",[t._v("If your subscription plan only offers a monthly billing cycle, you may omit the "),s("code",[t._v("yearly_id")]),t._v(" identifier from your plan configuration. Likewise, if your plan only offers a yearly billing cycle, you may omit the "),s("code",[t._v("monthly_id")]),t._v(" identifier.")]),t._v(" "),s("p",[t._v("In addition, you are free to supply a short description of the plan and a list of features relevant to the plan. This information will be displayed in the Spark billing portal.")]),t._v(" "),s("h2",{attrs:{id:"accessing-the-billing-portal"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#accessing-the-billing-portal"}},[t._v("#")]),t._v(" Accessing The Billing Portal")]),t._v(" "),s("p",[t._v("Once you have configured your Spark installation, you may access your application's billing portal at the "),s("code",[t._v("/billing")]),t._v(" URI. So, if your application is being served on "),s("code",[t._v("localhost")]),t._v(", you may access your application's billing portal at "),s("code",[t._v("http://localhost/billing")]),t._v(".")]),t._v(" "),s("p",[t._v("Of course, you may link to the billing portal from your application's dashboard however you see fit:")]),t._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("href")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("/billing"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n Manage Subscription\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("h2",{attrs:{id:"showing-a-link-to-the-terms-and-conditions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[t._v("#")]),t._v(" Showing A Link To The Terms And Conditions")]),t._v(" "),s("p",[t._v("Many applications display billing terms and conditions during checkout. Spark allows you to easily do the same within your application's billing portal. To get started, add a "),s("code",[t._v("terms_url")]),t._v(" configuration value in your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'terms_url'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/terms'")]),t._v("\n")])])]),s("p",[t._v("Once added, Spark will display a link pointing to "),s("code",[t._v("/terms")]),t._v(" in the billing portal.")])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/43.1e21ec9e.js b/.vuepress/dist/assets/js/23.c2854556.js similarity index 99% rename from .vuepress/dist/assets/js/43.1e21ec9e.js rename to .vuepress/dist/assets/js/23.c2854556.js index 98f9aa8..ccdd310 100644 --- a/.vuepress/dist/assets/js/43.1e21ec9e.js +++ b/.vuepress/dist/assets/js/23.c2854556.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[43],{439:function(t,a,s){"use strict";s.r(a);var e=s(55),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"cookbook"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#cookbook"}},[t._v("#")]),t._v(" Cookbook")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#team-billing"}},[t._v("Team Billing")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"team-billing"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#team-billing"}},[t._v("#")]),t._v(" Team Billing")]),t._v(" "),s("p",[t._v('Spark ships with "user" based billing by default. If your applications bills teams or a different model instead, you will need to adjust your Spark installation accordingly. We\'ll walk through these adjustments in the following documentation using a team billing implementation as an example.')]),t._v(" "),s("p",[t._v("To make the "),s("code",[t._v("App\\Models\\Team")]),t._v(" model our billable model, we first need to adjust Spark's default migrations. So, let's configure Spark to ignore its own default migrations and export the migrations to our application so that we can adjust them:")]),t._v(" "),s("h4",{attrs:{id:"customizing-the-migrations"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#customizing-the-migrations"}},[t._v("#")]),t._v(" Customizing The Migrations")]),t._v(" "),s("p",[t._v("To instruct Spark to ignore its migrations, call the "),s("code",[t._v("Spark::ignoreMigrations()")]),t._v(" method in the "),s("code",[t._v("register")]),t._v(" method of your application's "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ignoreMigrations")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("Next, execute the following Artisan command to publish the migrations:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-migrations\n")])])]),s("p",[t._v("Now that the migrations are published in the "),s("code",[t._v("/database/migrations")]),t._v(" directory, we need to change the name of the "),s("code",[t._v("2019_05_03_000001_add_spark_columns_to_users_table.php")]),t._v(" file to "),s("code",[t._v("2020_05_03_000001_add_spark_columns_to_teams_table.php")]),t._v('. Adjusting the "year" of the migration will ensure the migration is run after the '),s("code",[t._v("teams")]),t._v(" table is created in the database.")]),t._v(" "),s("p",[t._v("After renaming the migration, you may update its contents such that it updates the table definition of the "),s("code",[t._v("teams")]),t._v(" table instead of the "),s("code",[t._v("users")]),t._v(" table. Also, update the first column so that it is added after a field on the "),s("code",[t._v("teams")]),t._v(" table instead of "),s("code",[t._v("remember_token")]),t._v(".")]),t._v(" "),s("p",[t._v("Next, update the "),s("code",[t._v("subscriptions")]),t._v(" table migration to contain "),s("code",[t._v("team_id")]),t._v("instead of "),s("code",[t._v("user_id")]),t._v(". You should also ensure that you update the column in the migration's index as well.")]),t._v(" "),s("p",[t._v("Finally, you also need to update the migration of the "),s("code",[t._v("receipts")]),t._v(" table to use the "),s("code",[t._v("team_id")]),t._v(" column instead of "),s("code",[t._v("user_id")]),t._v(".")]),t._v(" "),s("h4",{attrs:{id:"updating-the-service-provider"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-service-provider"}},[t._v("#")]),t._v(" Updating The Service Provider")]),t._v(" "),s("p",[t._v("Now that the migrations have been updated, we should update the "),s("code",[t._v("SparkServiceProvider")]),t._v(" to reference the "),s("code",[t._v("Team")]),t._v(" model instead of the "),s("code",[t._v("User")]),t._v(" model:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("SparkServiceProvider")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServiceProvider")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Bootstrap any application services.\n *\n * @return void\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("boot")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Resolve the current team...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("currentTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Verify that the current user owns the team...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("id")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("user_id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkPlanEligibility")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Plan")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h4",{attrs:{id:"environment-variables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#environment-variables"}},[t._v("#")]),t._v(" Environment Variables")]),t._v(" "),s("p",[t._v("Next, update the "),s("code",[t._v("CASHIER_MODEL")]),t._v(" environment variable to use the "),s("code",[t._v("Team")]),t._v(" model instead of the "),s("code",[t._v("User")]),t._v(" model:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("CASHIER_MODEL")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team\n")])])]),s("h4",{attrs:{id:"updating-the-model"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-model"}},[t._v("#")]),t._v(" Updating The Model")]),t._v(" "),s("p",[t._v("Now we can update the "),s("code",[t._v("Team")]),t._v(" model to use the "),s("code",[t._v("Spark\\Billable")]),t._v(" trait and implement a "),s("code",[t._v("stripeEmail")]),t._v(" method that returns the team owner's email address to be displayed in the Stripe dashboard as the customer identifier:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JetstreamTeam")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("stripeEmail")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$this")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("owner")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("email")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h4",{attrs:{id:"spark-configuration-file"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#spark-configuration-file"}},[t._v("#")]),t._v(" Spark Configuration File")]),t._v(" "),s("p",[t._v("Finally, update your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file so that it defines a "),s("code",[t._v("team")]),t._v(" billable model:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'billables'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'team'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'model'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{418:function(t,a,s){"use strict";s.r(a);var e=s(55),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"cookbook"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#cookbook"}},[t._v("#")]),t._v(" Cookbook")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#team-billing"}},[t._v("Team Billing")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"team-billing"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#team-billing"}},[t._v("#")]),t._v(" Team Billing")]),t._v(" "),s("p",[t._v('Spark ships with "user" based billing by default. If your applications bills teams or a different model instead, you will need to adjust your Spark installation accordingly. We\'ll walk through these adjustments in the following documentation using a team billing implementation as an example.')]),t._v(" "),s("p",[t._v("To make the "),s("code",[t._v("App\\Models\\Team")]),t._v(" model our billable model, we first need to adjust Spark's default migrations. So, let's configure Spark to ignore its own default migrations and export the migrations to our application so that we can adjust them:")]),t._v(" "),s("h4",{attrs:{id:"customizing-the-migrations"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#customizing-the-migrations"}},[t._v("#")]),t._v(" Customizing The Migrations")]),t._v(" "),s("p",[t._v("To instruct Spark to ignore its migrations, call the "),s("code",[t._v("Spark::ignoreMigrations()")]),t._v(" method in the "),s("code",[t._v("register")]),t._v(" method of your application's "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ignoreMigrations")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("Next, execute the following Artisan command to publish the migrations:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-migrations\n")])])]),s("p",[t._v("Now that the migrations are published in the "),s("code",[t._v("/database/migrations")]),t._v(" directory, we need to change the name of the "),s("code",[t._v("2019_05_03_000001_add_spark_columns_to_users_table.php")]),t._v(" file to "),s("code",[t._v("2020_05_03_000001_add_spark_columns_to_teams_table.php")]),t._v('. Adjusting the "year" of the migration will ensure the migration is run after the '),s("code",[t._v("teams")]),t._v(" table is created in the database.")]),t._v(" "),s("p",[t._v("After renaming the migration, you may update its contents such that it updates the table definition of the "),s("code",[t._v("teams")]),t._v(" table instead of the "),s("code",[t._v("users")]),t._v(" table. Also, update the first column so that it is added after a field on the "),s("code",[t._v("teams")]),t._v(" table instead of "),s("code",[t._v("remember_token")]),t._v(".")]),t._v(" "),s("p",[t._v("Next, update the "),s("code",[t._v("subscriptions")]),t._v(" table migration to contain "),s("code",[t._v("team_id")]),t._v("instead of "),s("code",[t._v("user_id")]),t._v(". You should also ensure that you update the column in the migration's index as well.")]),t._v(" "),s("p",[t._v("Finally, you also need to update the migration of the "),s("code",[t._v("receipts")]),t._v(" table to use the "),s("code",[t._v("team_id")]),t._v(" column instead of "),s("code",[t._v("user_id")]),t._v(".")]),t._v(" "),s("h4",{attrs:{id:"updating-the-service-provider"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-service-provider"}},[t._v("#")]),t._v(" Updating The Service Provider")]),t._v(" "),s("p",[t._v("Now that the migrations have been updated, we should update the "),s("code",[t._v("SparkServiceProvider")]),t._v(" to reference the "),s("code",[t._v("Team")]),t._v(" model instead of the "),s("code",[t._v("User")]),t._v(" model:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("SparkServiceProvider")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServiceProvider")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Bootstrap any application services.\n *\n * @return void\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("boot")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Resolve the current team...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("currentTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Verify that the current user owns the team...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("id")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("user_id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkPlanEligibility")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Plan")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h4",{attrs:{id:"environment-variables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#environment-variables"}},[t._v("#")]),t._v(" Environment Variables")]),t._v(" "),s("p",[t._v("Next, update the "),s("code",[t._v("CASHIER_MODEL")]),t._v(" environment variable to use the "),s("code",[t._v("Team")]),t._v(" model instead of the "),s("code",[t._v("User")]),t._v(" model:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("CASHIER_MODEL")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team\n")])])]),s("h4",{attrs:{id:"updating-the-model"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-model"}},[t._v("#")]),t._v(" Updating The Model")]),t._v(" "),s("p",[t._v("Now we can update the "),s("code",[t._v("Team")]),t._v(" model to use the "),s("code",[t._v("Spark\\Billable")]),t._v(" trait and implement a "),s("code",[t._v("stripeEmail")]),t._v(" method that returns the team owner's email address to be displayed in the Stripe dashboard as the customer identifier:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JetstreamTeam")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("stripeEmail")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$this")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("owner")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("email")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h4",{attrs:{id:"spark-configuration-file"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#spark-configuration-file"}},[t._v("#")]),t._v(" Spark Configuration File")]),t._v(" "),s("p",[t._v("Finally, update your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file so that it defines a "),s("code",[t._v("team")]),t._v(" billable model:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'billables'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'team'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'model'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/24.7ec9d664.js b/.vuepress/dist/assets/js/24.9d499e01.js similarity index 99% rename from .vuepress/dist/assets/js/24.7ec9d664.js rename to .vuepress/dist/assets/js/24.9d499e01.js index a332343..68b936e 100644 --- a/.vuepress/dist/assets/js/24.7ec9d664.js +++ b/.vuepress/dist/assets/js/24.9d499e01.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{420:function(t,a,s){"use strict";s.r(a);var n=s(55),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"customization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#customization"}},[t._v("#")]),t._v(" Customization")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#branding"}},[t._v("Branding")]),s("ul",[s("li",[s("a",{attrs:{href:"#brand-logo"}},[t._v("Brand Logo")])]),s("li",[s("a",{attrs:{href:"#brand-color"}},[t._v("Brand Color")])]),s("li",[s("a",{attrs:{href:"#font"}},[t._v("Font")])])])]),s("li",[s("a",{attrs:{href:"#localization"}},[t._v("Localization")])]),s("li",[s("a",{attrs:{href:"#migrations"}},[t._v("Migrations")])]),s("li",[s("a",{attrs:{href:"#webhooks"}},[t._v("Webhooks")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"branding"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#branding"}},[t._v("#")]),t._v(" Branding")]),t._v(" "),s("p",[t._v("Although Spark's billing portal is intended to be an isolated part of your application that is entirely managed by Spark, you can make some small customizations to the branding logo and color used by Spark.")]),t._v(" "),s("h3",{attrs:{id:"brand-logo"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#brand-logo"}},[t._v("#")]),t._v(" Brand Logo")]),t._v(" "),s("p",[t._v("To customize the logo used at the top left of the Spark billing portal, you may specify a configuration value for the "),s("code",[t._v("brand.logo")]),t._v(" configuration item within your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file. This configuration value should contain an absolute path to the SVG file of the logo you would like to use:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'brand'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'logo'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("realpath")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("__DIR__")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/../public/img/logo.svg'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("SVG Sizing")]),t._v(" "),s("p",[t._v("You may need to adjust the size and width of your SVG logo by modifying its width in the SVG file itself.")])]),t._v(" "),s("h3",{attrs:{id:"brand-color"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#brand-color"}},[t._v("#")]),t._v(" Brand Color")]),t._v(" "),s("p",[t._v("To customize the color used as the background color of the button elements within the Spark billing portal, you may specify a value for the "),s("code",[t._v("brand.color")]),t._v(" configuration item within your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file. This configuration value should be a valid hex code or correspond to a background color offered by the "),s("a",{attrs:{href:"https://tailwindcss.com/docs/customizing-colors",target:"_blank",rel:"noopener noreferrer"}},[t._v("Tailwind CSS framework"),s("OutboundLink")],1),t._v(":")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'brand'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'bg-indigo-600'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Or...")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'#c5b358'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("h3",{attrs:{id:"font"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#font"}},[t._v("#")]),t._v(" Font")]),t._v(" "),s("p",[t._v("To customize the font used by the Spark billing portal, you should export Spark's views using the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-views\n")])])]),s("p",[t._v("Next, within the "),s("code",[t._v("resources/views/vendor/spark/app.blade.php")]),t._v(" template, you may define your own "),s("code",[t._v("font-sans")]),t._v(" CSS class at the bottom of the templates "),s("code",[t._v("head")]),t._v(" section:")]),t._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("head")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("\x3c!-- ...... --\x3e")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("style")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token style"}},[s("span",{pre:!0,attrs:{class:"token language-css"}},[t._v("\n "),s("span",{pre:!0,attrs:{class:"token selector"}},[t._v(".font-sans")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("font-family")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Your Custom Font'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n ")])]),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("h2",{attrs:{id:"localization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#localization"}},[t._v("#")]),t._v(" Localization")]),t._v(" "),s("p",[t._v("You may localize / translate all of the text within the Spark billing portal. To publish the Spark localization file, you may use the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-lang\n")])])]),s("p",[t._v("This command will publish a "),s("code",[t._v("resources/lang/spark/en.json")]),t._v(" file containing translation keys and values for the English language. You may copy this file and translate it to the language of your choice. For more information on how to use Laravel's translation features, please consult the "),s("a",{attrs:{href:"https://laravel.com/docs/localization#using-translation-strings-as-keys",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel localization documentation"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"migrations"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#migrations"}},[t._v("#")]),t._v(" Migrations")]),t._v(" "),s("p",[t._v("Most commonly, applications bill individual users for monthly and yearly subscription plans. However, your application may choose to bill some other type of model, such as a team, organization, band, etc.")]),t._v(" "),s("p",[t._v("In that case, you should add "),s("code",[t._v("Spark::ignoreMigrations()")]),t._v(" in the register method of your application's "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("SparkServiceProvider")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServiceProvider")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Register any application services.\n *\n * @return void\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ignoreMigrations")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("Next, you should publish the Spark migrations by running the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"spark-migrations"')]),t._v("\n")])])]),s("p",[t._v("Finally, you should inspect the published migrations and update the "),s("code",[t._v("2019_05_03_000001_add_spark_columns_to_users_table.php")]),t._v(" file to add the columns needed by Spark to the table that will be used by your application's billable model.")]),t._v(" "),s("h2",{attrs:{id:"webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks"}},[t._v("#")]),t._v(" Webhooks")]),t._v(" "),s("p",[t._v("Spark and Cashier automatically handle subscription cancellations for failed charges and other common Stripe webhook events. However, if you have additional webhook events you would like to handle, you may do so by extending the Spark webhook controller.")]),t._v(" "),s("p",[t._v("Your controller's method names should correspond to Cashier's controller conventions. Specifically, methods should be prefixed with "),s("code",[t._v("handle")]),t._v(' and the "camel case" name of the webhook you wish to handle. For example, if you wish to handle the '),s("code",[t._v("invoice.payment_succeeded")]),t._v(" webhook, you should add a "),s("code",[t._v("handleInvoicePaymentSucceeded")]),t._v(" method to the controller:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[t._v("")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'logo'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("realpath")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("__DIR__")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/../public/img/logo.svg'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("SVG Sizing")]),t._v(" "),s("p",[t._v("You may need to adjust the size and width of your SVG logo by modifying its width in the SVG file itself.")])]),t._v(" "),s("h3",{attrs:{id:"brand-color"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#brand-color"}},[t._v("#")]),t._v(" Brand Color")]),t._v(" "),s("p",[t._v("To customize the color used as the background color of the button elements within the Spark billing portal, you may specify a value for the "),s("code",[t._v("brand.color")]),t._v(" configuration item within your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file. This configuration value should be a valid hex code or correspond to a background color offered by the "),s("a",{attrs:{href:"https://tailwindcss.com/docs/customizing-colors",target:"_blank",rel:"noopener noreferrer"}},[t._v("Tailwind CSS framework"),s("OutboundLink")],1),t._v(":")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'brand'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'bg-indigo-600'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Or...")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'#c5b358'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("h3",{attrs:{id:"font"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#font"}},[t._v("#")]),t._v(" Font")]),t._v(" "),s("p",[t._v("To customize the font used by the Spark billing portal, you should export Spark's views using the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-views\n")])])]),s("p",[t._v("Next, within the "),s("code",[t._v("resources/views/vendor/spark/app.blade.php")]),t._v(" template, you may define your own "),s("code",[t._v("font-sans")]),t._v(" CSS class at the bottom of the templates "),s("code",[t._v("head")]),t._v(" section:")]),t._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("head")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("\x3c!-- ...... --\x3e")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("style")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token style"}},[s("span",{pre:!0,attrs:{class:"token language-css"}},[t._v("\n "),s("span",{pre:!0,attrs:{class:"token selector"}},[t._v(".font-sans")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("font-family")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Your Custom Font'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n ")])]),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("h2",{attrs:{id:"localization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#localization"}},[t._v("#")]),t._v(" Localization")]),t._v(" "),s("p",[t._v("You may localize / translate all of the text within the Spark billing portal. To publish the Spark localization file, you may use the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-lang\n")])])]),s("p",[t._v("This command will publish a "),s("code",[t._v("resources/lang/spark/en.json")]),t._v(" file containing translation keys and values for the English language. You may copy this file and translate it to the language of your choice. For more information on how to use Laravel's translation features, please consult the "),s("a",{attrs:{href:"https://laravel.com/docs/localization#using-translation-strings-as-keys",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel localization documentation"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"migrations"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#migrations"}},[t._v("#")]),t._v(" Migrations")]),t._v(" "),s("p",[t._v("Most commonly, applications bill individual users for monthly and yearly subscription plans. However, your application may choose to bill some other type of model, such as a team, organization, band, etc.")]),t._v(" "),s("p",[t._v("In that case, you should add "),s("code",[t._v("Spark::ignoreMigrations()")]),t._v(" in the register method of your application's "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("SparkServiceProvider")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServiceProvider")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Register any application services.\n *\n * @return void\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ignoreMigrations")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("Next, you should publish the Spark migrations by running the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"spark-migrations"')]),t._v("\n")])])]),s("p",[t._v("Finally, you should inspect the published migrations and update the "),s("code",[t._v("2019_05_03_000001_add_spark_columns_to_users_table.php")]),t._v(" file to add the columns needed by Spark to the table that will be used by your application's billable model.")]),t._v(" "),s("h2",{attrs:{id:"webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks"}},[t._v("#")]),t._v(" Webhooks")]),t._v(" "),s("p",[t._v("Spark and Cashier automatically handle subscription cancellations for failed charges and other common Stripe webhook events. However, if you have additional webhook events you would like to handle, you may do so by extending the Spark webhook controller.")]),t._v(" "),s("p",[t._v("Your controller's method names should correspond to Cashier's controller conventions. Specifically, methods should be prefixed with "),s("code",[t._v("handle")]),t._v(' and the "camel case" name of the webhook you wish to handle. For example, if you wish to handle the '),s("code",[t._v("invoice.payment_succeeded")]),t._v(" webhook, you should add a "),s("code",[t._v("handleInvoicePaymentSucceeded")]),t._v(" method to the controller:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[t._v("")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("VerifyBillableIsSubscribed")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Once the middleware has been registered, you may attach it to any of your application's route definitions:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Route")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("post")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/projects'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ProjectController")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'store'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("middleware")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'auth'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("If the user has an active subscription, the request will continue to execute normally. However, if the user does not have an active subscription, they will be redirected to your application's Spark billing portal. If the request is an XHR request, a response with a 402 HTTP status code will be returned to the client.")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("Manually Inspecting Subscription States")]),t._v(" "),a("p",[t._v("Of course, you may always manually inspect a billable model's subscription status using the "),a("a",{attrs:{href:"https://laravel.com/docs/billing#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),a("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan.")])])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{422:function(t,s,a){"use strict";a.r(s);var e=a(55),n=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"middleware"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#middleware"}},[t._v("#")]),t._v(" Middleware")]),t._v(" "),a("p"),a("div",{staticClass:"table-of-contents"},[a("ul")]),a("p"),t._v(" "),a("p",[t._v("When building a subscription based application, you will commonly need to restrict access to certain routes to users that have an active subscription. For example, you may not want to let a user create a project if they are not subscribed to a billing plan. For that reason, Spark provides a convenient subscription verification "),a("a",{attrs:{href:"https://laravel.com/docs/middleware",target:"_blank",rel:"noopener noreferrer"}},[t._v("middleware"),a("OutboundLink")],1),t._v(" that you may register with your application.")]),t._v(" "),a("p",[t._v("To get started, register Spark's subscription verification middleware in your HTTP kernel's "),a("code",[t._v("$routeMiddleware")]),t._v(" array. Your application's HTTP kernel is typically located at "),a("code",[t._v("app/Http/Kernel.php")]),t._v(":")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Middleware"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("VerifyBillableIsSubscribed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("protected")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$routeMiddleware")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("VerifyBillableIsSubscribed")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Once the middleware has been registered, you may attach it to any of your application's route definitions:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Route")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("post")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/projects'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ProjectController")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'store'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("middleware")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'auth'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("If the user has an active subscription, the request will continue to execute normally. However, if the user does not have an active subscription, they will be redirected to your application's Spark billing portal. If the request is an XHR request, a response with a 402 HTTP status code will be returned to the client.")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("Manually Inspecting Subscription States")]),t._v(" "),a("p",[t._v("Of course, you may always manually inspect a billable model's subscription status using the "),a("a",{attrs:{href:"https://laravel.com/docs/billing#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),a("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan.")])])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/27.8166b3a7.js b/.vuepress/dist/assets/js/27.47550fce.js similarity index 97% rename from .vuepress/dist/assets/js/27.8166b3a7.js rename to .vuepress/dist/assets/js/27.47550fce.js index 1e59c8f..c257d88 100644 --- a/.vuepress/dist/assets/js/27.8166b3a7.js +++ b/.vuepress/dist/assets/js/27.47550fce.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{421:function(t,s,a){"use strict";a.r(s);var e=a(55),n=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"taxes"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#taxes"}},[t._v("#")]),t._v(" Taxes")]),t._v(" "),a("p",[t._v("Spark may be configured to calculate and apply European Union VAT tax to subscriptions.")]),t._v(" "),a("p",[t._v("To get started, you should uncomment the "),a("code",[t._v("Features::euVatCollection()")]),t._v(" line within your application's "),a("code",[t._v("config/spark.php")]),t._v(" configuration file. The value provided for the "),a("code",[t._v("home-country")]),t._v(" option should be the two-character country code corresponding to the country where your business is located:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Features")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Features")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("euVatCollection")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'home-country'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'BE'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),a("p",[t._v("Once you have completed these steps, Spark will automatically gather customer billing address information as well as VAT Number and apply the correct VAT based on the customer's location.")])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{446:function(t,s,a){"use strict";a.r(s);var e=a(55),n=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"taxes"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#taxes"}},[t._v("#")]),t._v(" Taxes")]),t._v(" "),a("p",[t._v("Spark may be configured to calculate and apply European Union VAT tax to subscriptions.")]),t._v(" "),a("p",[t._v("To get started, you should uncomment the "),a("code",[t._v("Features::euVatCollection()")]),t._v(" line within your application's "),a("code",[t._v("config/spark.php")]),t._v(" configuration file. The value provided for the "),a("code",[t._v("home-country")]),t._v(" option should be the two-character country code corresponding to the country where your business is located:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Features")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Features")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("euVatCollection")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'home-country'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'BE'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),a("p",[t._v("Once you have completed these steps, Spark will automatically gather customer billing address information as well as VAT Number and apply the correct VAT based on the customer's location.")])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/28.d97c5e89.js b/.vuepress/dist/assets/js/28.e31447b8.js similarity index 99% rename from .vuepress/dist/assets/js/28.d97c5e89.js rename to .vuepress/dist/assets/js/28.e31447b8.js index c502be1..58fefe0 100644 --- a/.vuepress/dist/assets/js/28.d97c5e89.js +++ b/.vuepress/dist/assets/js/28.e31447b8.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{423:function(t,s,a){"use strict";a.r(s);var n=a(55),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"testing"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#testing"}},[t._v("#")]),t._v(" Testing")]),t._v(" "),a("p"),a("div",{staticClass:"table-of-contents"},[a("ul",[a("li",[a("a",{attrs:{href:"#factories"}},[t._v("Factories")])])])]),a("p"),t._v(" "),a("h2",{attrs:{id:"factories"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#factories"}},[t._v("#")]),t._v(" Factories")]),t._v(" "),a("p",[t._v('While developing your application, you will likely want to "stub" a subscription record in your application\'s database so that calls to the '),a("code",[t._v("$billable->subscribed()")]),t._v(" method return "),a("code",[t._v("true")]),t._v(".")]),t._v(" "),a("p",[t._v('To accomplish this, you may add a "state" method to your billable model\'s '),a("a",{attrs:{href:"https://laravel.com/docs/database-testing#defining-model-factories",target:"_blank",rel:"noopener noreferrer"}},[t._v("factory class"),a("OutboundLink")],1),t._v(". Typically, this will be your application's "),a("code",[t._v("UserFactory")]),t._v(" class. Below you will find an example state method implementation; however, you are free to adjust this to your application's own needs:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Indicate that the user should have a subscription plan.\n *\n * @param string $planId\n * @return \\Illuminate\\Database\\Eloquent\\Factories\\Factory\n */")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$this")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("afterCreating")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$subscription")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscriptions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'default'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_id'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Str")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("random")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_status'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'active'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_plan'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'quantity'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$subscription")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("items")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_id'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Str")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("random")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_plan'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'quantity'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Once you have define the state method, you may use it when creating models via your factory:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("factory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plan_id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// true")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{447:function(t,s,a){"use strict";a.r(s);var n=a(55),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"testing"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#testing"}},[t._v("#")]),t._v(" Testing")]),t._v(" "),a("p"),a("div",{staticClass:"table-of-contents"},[a("ul",[a("li",[a("a",{attrs:{href:"#factories"}},[t._v("Factories")])])])]),a("p"),t._v(" "),a("h2",{attrs:{id:"factories"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#factories"}},[t._v("#")]),t._v(" Factories")]),t._v(" "),a("p",[t._v('While developing your application, you will likely want to "stub" a subscription record in your application\'s database so that calls to the '),a("code",[t._v("$billable->subscribed()")]),t._v(" method return "),a("code",[t._v("true")]),t._v(".")]),t._v(" "),a("p",[t._v('To accomplish this, you may add a "state" method to your billable model\'s '),a("a",{attrs:{href:"https://laravel.com/docs/database-testing#defining-model-factories",target:"_blank",rel:"noopener noreferrer"}},[t._v("factory class"),a("OutboundLink")],1),t._v(". Typically, this will be your application's "),a("code",[t._v("UserFactory")]),t._v(" class. Below you will find an example state method implementation; however, you are free to adjust this to your application's own needs:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Indicate that the user should have a subscription plan.\n *\n * @param string $planId\n * @return \\Illuminate\\Database\\Eloquent\\Factories\\Factory\n */")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$this")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("afterCreating")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$subscription")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscriptions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'default'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_id'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Str")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("random")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_status'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'active'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_plan'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'quantity'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$subscription")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("items")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_id'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Str")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("random")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_plan'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'quantity'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Once you have define the state method, you may use it when creating models via your factory:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("factory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plan_id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// true")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/29.1cb997ca.js b/.vuepress/dist/assets/js/29.54c4da39.js similarity index 99% rename from .vuepress/dist/assets/js/29.1cb997ca.js rename to .vuepress/dist/assets/js/29.54c4da39.js index f7e1632..98ac8b8 100644 --- a/.vuepress/dist/assets/js/29.1cb997ca.js +++ b/.vuepress/dist/assets/js/29.54c4da39.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{424:function(t,s,a){"use strict";a.r(s);var n=a(55),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"upgrade"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#upgrade"}},[t._v("#")]),t._v(" Upgrade")]),t._v(" "),a("p"),a("div",{staticClass:"table-of-contents"},[a("ul",[a("li",[a("a",{attrs:{href:"#upgrading-to-spark-stripe-v1-0-5"}},[t._v("Upgrading to Spark-Stripe v1.0.5")])])])]),a("p"),t._v(" "),a("h2",{attrs:{id:"upgrading-to-spark-stripe-v1-0-5"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#upgrading-to-spark-stripe-v1-0-5"}},[t._v("#")]),t._v(" Upgrading to Spark-Stripe v1.0.5")]),t._v(" "),a("h4",{attrs:{id:"updating-the-configuration-file"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-configuration-file"}},[t._v("#")]),t._v(" Updating The Configuration File")]),t._v(" "),a("p",[t._v("Spark-Stripe v1.0.5 introduces a new format for enabling features in the configuration file. To use the new format, add the following lines to your "),a("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Features")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Features::euVatCollection(['home-country' => 'BE']),")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Features::receiptEmails(['custom-addresses' => true]),")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Features")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("paymentNotificationEmails")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),a("p",[t._v("Next, uncomment the features you want to use in your application and remove the old corresponding configuration keys:")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("collects_eu_vat")])]),t._v(" "),a("li",[a("code",[t._v("sends_receipt_emails")])]),t._v(" "),a("li",[a("code",[t._v("sends_payment_notification_emails")])])]),t._v(" "),a("h4",{attrs:{id:"collecting-billing-email-addresses"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#collecting-billing-email-addresses"}},[t._v("#")]),t._v(" Collecting Billing Email Addresses")]),t._v(" "),a("p",[t._v("Spark-Stripe v1.0.5 introduces the ability to email receipts to a custom billing address that the customer provides. This is typically used to email receipts directly to an accountant.")]),t._v(" "),a("p",[t._v("To support this feature, you need to create a new migration in your application and add the following schema modification in the migration's "),a("code",[t._v("up()")]),t._v(" method:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("up")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("hasColumn")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'users'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'receipt_emails'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("table")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'users'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Blueprint")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("text")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'receipt_emails'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("after")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Make sure to run the migration against the table that corresponds to your billable model.")]),t._v(" "),a("p",[t._v("To enable the feature, uncomment the "),a("code",[t._v("Features::receiptEmails()")]),t._v(" line in your "),a("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Features::euVatCollection(['home-country' => 'BE']),")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Features")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("receiptEmails")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'custom-addresses'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Features")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("paymentNotificationEmailsSending")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{448:function(t,s,a){"use strict";a.r(s);var n=a(55),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"upgrade"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#upgrade"}},[t._v("#")]),t._v(" Upgrade")]),t._v(" "),a("p"),a("div",{staticClass:"table-of-contents"},[a("ul",[a("li",[a("a",{attrs:{href:"#upgrading-to-spark-stripe-v1-0-5"}},[t._v("Upgrading to Spark-Stripe v1.0.5")])])])]),a("p"),t._v(" "),a("h2",{attrs:{id:"upgrading-to-spark-stripe-v1-0-5"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#upgrading-to-spark-stripe-v1-0-5"}},[t._v("#")]),t._v(" Upgrading to Spark-Stripe v1.0.5")]),t._v(" "),a("h4",{attrs:{id:"updating-the-configuration-file"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-configuration-file"}},[t._v("#")]),t._v(" Updating The Configuration File")]),t._v(" "),a("p",[t._v("Spark-Stripe v1.0.5 introduces a new format for enabling features in the configuration file. To use the new format, add the following lines to your "),a("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Features")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Features::euVatCollection(['home-country' => 'BE']),")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Features::receiptEmails(['custom-addresses' => true]),")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Features")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("paymentNotificationEmails")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),a("p",[t._v("Next, uncomment the features you want to use in your application and remove the old corresponding configuration keys:")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("collects_eu_vat")])]),t._v(" "),a("li",[a("code",[t._v("sends_receipt_emails")])]),t._v(" "),a("li",[a("code",[t._v("sends_payment_notification_emails")])])]),t._v(" "),a("h4",{attrs:{id:"collecting-billing-email-addresses"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#collecting-billing-email-addresses"}},[t._v("#")]),t._v(" Collecting Billing Email Addresses")]),t._v(" "),a("p",[t._v("Spark-Stripe v1.0.5 introduces the ability to email receipts to a custom billing address that the customer provides. This is typically used to email receipts directly to an accountant.")]),t._v(" "),a("p",[t._v("To support this feature, you need to create a new migration in your application and add the following schema modification in the migration's "),a("code",[t._v("up()")]),t._v(" method:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("up")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("hasColumn")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'users'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'receipt_emails'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("table")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'users'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Blueprint")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("text")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'receipt_emails'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("after")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Make sure to run the migration against the table that corresponds to your billable model.")]),t._v(" "),a("p",[t._v("To enable the feature, uncomment the "),a("code",[t._v("Features::receiptEmails()")]),t._v(" line in your "),a("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Features::euVatCollection(['home-country' => 'BE']),")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Features")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("receiptEmails")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'custom-addresses'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Features")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("paymentNotificationEmailsSending")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/50.a45b7f9f.js b/.vuepress/dist/assets/js/30.8819ef2d.js similarity index 83% rename from .vuepress/dist/assets/js/50.a45b7f9f.js rename to .vuepress/dist/assets/js/30.8819ef2d.js index ef128b9..e4c865a 100644 --- a/.vuepress/dist/assets/js/50.a45b7f9f.js +++ b/.vuepress/dist/assets/js/30.8819ef2d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[50],{447:function(t,e,n){"use strict";n.r(e);var s=n(55),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("meta",{attrs:{"http-equiv":"refresh",content:"0;url=/docs/2.x/introduction.html"}})])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{423:function(t,e,n){"use strict";n.r(e);var s=n(55),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("meta",{attrs:{"http-equiv":"refresh",content:"0;url=/docs/2.x/introduction.html"}})])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/31.10d0fc8c.js b/.vuepress/dist/assets/js/31.c977b44e.js similarity index 99% rename from .vuepress/dist/assets/js/31.10d0fc8c.js rename to .vuepress/dist/assets/js/31.c977b44e.js index f9cf669..6c71aae 100644 --- a/.vuepress/dist/assets/js/31.10d0fc8c.js +++ b/.vuepress/dist/assets/js/31.c977b44e.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[31],{425:function(a,t,s){"use strict";s.r(t);var e=s(55),r=Object(e.a)({},(function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h1",{attrs:{id:"installation"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[a._v("#")]),a._v(" Installation")]),a._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#installing-spark-via-composer"}},[a._v("Installing Spark Via Composer")])]),s("li",[s("a",{attrs:{href:"#authenticating-spark-in-continuous-integration-ci-environments"}},[a._v("Authenticating Spark in Continuous Integration (CI) Environments")])])])]),s("p"),a._v(" "),s("h2",{attrs:{id:"installing-spark-via-composer"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#installing-spark-via-composer"}},[a._v("#")]),a._v(" Installing Spark Via Composer")]),a._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[a._v("License")]),a._v(" "),s("p",[a._v("Before installing Spark, you will need to purchase a "),s("a",{attrs:{href:"https://spark.laravel.com/licenses",target:"_blank",rel:"noopener noreferrer"}},[a._v("Spark license"),s("OutboundLink")],1),a._v(". You can purchase a Spark license via the Spark dashboard.")])]),a._v(" "),s("p",[a._v("To get started installing Spark, add the Spark repository to your application's "),s("code",[a._v("composer.json")]),a._v(" file:")]),a._v(" "),s("div",{staticClass:"language-json extra-class"},[s("pre",{pre:!0,attrs:{class:"language-json"}},[s("code",[s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"repositories"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"composer"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"url"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"https://spark.laravel.com"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n")])])]),s("p",[a._v("Next, you may add the "),s("code",[a._v("laravel/spark-paddle")]),a._v(" or "),s("code",[a._v("laravel/spark-stripe")]),a._v(" package to the list of required packages in your "),s("code",[a._v("composer.json")]),a._v(" file:")]),a._v(" "),s("div",{staticClass:"language-json extra-class"},[s("pre",{pre:!0,attrs:{class:"language-json"}},[s("code",[s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"require"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"php"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^8.0"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"laravel/framework"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^9.0"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"laravel/spark-paddle"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^1.0"')]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n")])])]),s("p",[a._v("After your "),s("code",[a._v("composer.json")]),a._v(" file has been updated, run the "),s("code",[a._v("composer update")]),a._v(" command in your console terminal:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("composer")]),a._v(" update\n")])])]),s("p",[a._v("When running "),s("code",[a._v("composer update")]),a._v(", you will be prompted to provide your login credentials for the Spark website. These credentials will authenticate your Composer session as having permission to download the Spark source code. To avoid manually typing these credentials, you may create a "),s("a",{attrs:{href:"https://getcomposer.org/doc/articles/http-basic-authentication.md",target:"_blank",rel:"noopener noreferrer"}},[a._v("Composer auth.json file"),s("OutboundLink")],1),a._v(" and use your "),s("a",{attrs:{href:"https://spark.laravel.com/user/api-tokens",target:"_blank",rel:"noopener noreferrer"}},[a._v("API token"),s("OutboundLink")],1),a._v(" in place of your password:")]),a._v(" "),s("div",{staticClass:"language-json extra-class"},[s("pre",{pre:!0,attrs:{class:"language-json"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"http-basic"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"spark.laravel.com"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"username"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"taylor@example.com"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"password"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"your-api-token"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("You may quickly create an "),s("code",[a._v("auth.json")]),a._v(" file via your terminal using the following command. As mentioned previously, you may create an API token via the "),s("a",{attrs:{href:"https://spark.laravel.com/user/api-tokens",target:"_blank",rel:"noopener noreferrer"}},[a._v("Spark dashboard"),s("OutboundLink")],1),a._v(". This token may be used as a substitute for your password when creating a Composer "),s("code",[a._v("auth.json")]),a._v(" file:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("composer")]),a._v(" config http-basic.spark.laravel.com taylor@example.com your-api-token\n")])])]),s("div",{staticClass:"custom-block danger"},[s("p",{staticClass:"custom-block-title"},[a._v("The `auth.json` File")]),a._v(" "),s("p",[a._v("You should not commit your application's "),s("code",[a._v("auth.json")]),a._v(" file into source control.")])]),a._v(" "),s("p",[a._v("Once the package is installed via Composer, run the "),s("code",[a._v("spark:install")]),a._v(" Artisan command:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("php artisan spark:install\n")])])]),s("p",[a._v("Finally, run the "),s("code",[a._v("migrate")]),a._v(" Artisan command:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("php artisan migrate\n")])])]),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[a._v("Stripe Billables")]),a._v(" "),s("p",[a._v("If you are using the Stripe edition of Spark and plan to bill a model other than the "),s("code",[a._v("App\\Models\\User")]),a._v(" model, you should follow "),s("RouterLink",{attrs:{to:"/2.x/spark-stripe/customization.html#migrations"}},[a._v("these instructions")]),a._v(" before running the migration command.")],1)]),a._v(" "),s("p",[a._v("That's it! Next, you may navigate to your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file and begin configuring your Spark installation.")]),a._v(" "),s("h2",{attrs:{id:"authenticating-spark-in-continuous-integration-ci-environments"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#authenticating-spark-in-continuous-integration-ci-environments"}},[a._v("#")]),a._v(" Authenticating Spark in Continuous Integration (CI) Environments")]),a._v(" "),s("p",[a._v("It's not advised to store your "),s("code",[a._v("auth.json")]),a._v(" file inside your project's version control repository. However, there may be times you wish to download Spark inside a CI environment like "),s("a",{attrs:{href:"https://chipperci.com/",target:"_blank",rel:"noopener noreferrer"}},[a._v("Chipper CI"),s("OutboundLink")],1),a._v(". For instance, you may wish to run tests for any custom tools you create. To authenticate Spark in these situations, you can use Composer to set the configuration option inside your CI system's pipeline, injecting environment variables containing the credentials you use to login to the Spark dashboard and a valid "),s("a",{attrs:{href:"https://spark.laravel.com/users/api-tokens",target:"_blank",rel:"noopener noreferrer"}},[a._v("Spark dashboard API token"),s("OutboundLink")],1),a._v(":")]),a._v(" "),s("div",{staticClass:"language-sh extra-class"},[s("pre",{pre:!0,attrs:{class:"language-sh"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("composer")]),a._v(" config http-basic.spark.laravel.com "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("${SPARK_USERNAME}")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("${SPARK_API_TOKEN}")]),a._v("\n")])])])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[31],{424:function(a,t,s){"use strict";s.r(t);var e=s(55),r=Object(e.a)({},(function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h1",{attrs:{id:"installation"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[a._v("#")]),a._v(" Installation")]),a._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#installing-spark-via-composer"}},[a._v("Installing Spark Via Composer")])]),s("li",[s("a",{attrs:{href:"#authenticating-spark-in-continuous-integration-ci-environments"}},[a._v("Authenticating Spark in Continuous Integration (CI) Environments")])])])]),s("p"),a._v(" "),s("h2",{attrs:{id:"installing-spark-via-composer"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#installing-spark-via-composer"}},[a._v("#")]),a._v(" Installing Spark Via Composer")]),a._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[a._v("License")]),a._v(" "),s("p",[a._v("Before installing Spark, you will need to purchase a "),s("a",{attrs:{href:"https://spark.laravel.com/licenses",target:"_blank",rel:"noopener noreferrer"}},[a._v("Spark license"),s("OutboundLink")],1),a._v(". You can purchase a Spark license via the Spark dashboard.")])]),a._v(" "),s("p",[a._v("To get started installing Spark, add the Spark repository to your application's "),s("code",[a._v("composer.json")]),a._v(" file:")]),a._v(" "),s("div",{staticClass:"language-json extra-class"},[s("pre",{pre:!0,attrs:{class:"language-json"}},[s("code",[s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"repositories"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"composer"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"url"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"https://spark.laravel.com"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n")])])]),s("p",[a._v("Next, you may add the "),s("code",[a._v("laravel/spark-paddle")]),a._v(" or "),s("code",[a._v("laravel/spark-stripe")]),a._v(" package to the list of required packages in your "),s("code",[a._v("composer.json")]),a._v(" file:")]),a._v(" "),s("div",{staticClass:"language-json extra-class"},[s("pre",{pre:!0,attrs:{class:"language-json"}},[s("code",[s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"require"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"php"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^8.0"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"laravel/framework"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^9.0"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"laravel/spark-paddle"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^1.0"')]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n")])])]),s("p",[a._v("After your "),s("code",[a._v("composer.json")]),a._v(" file has been updated, run the "),s("code",[a._v("composer update")]),a._v(" command in your console terminal:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("composer")]),a._v(" update\n")])])]),s("p",[a._v("When running "),s("code",[a._v("composer update")]),a._v(", you will be prompted to provide your login credentials for the Spark website. These credentials will authenticate your Composer session as having permission to download the Spark source code. To avoid manually typing these credentials, you may create a "),s("a",{attrs:{href:"https://getcomposer.org/doc/articles/http-basic-authentication.md",target:"_blank",rel:"noopener noreferrer"}},[a._v("Composer auth.json file"),s("OutboundLink")],1),a._v(" and use your "),s("a",{attrs:{href:"https://spark.laravel.com/user/api-tokens",target:"_blank",rel:"noopener noreferrer"}},[a._v("API token"),s("OutboundLink")],1),a._v(" in place of your password:")]),a._v(" "),s("div",{staticClass:"language-json extra-class"},[s("pre",{pre:!0,attrs:{class:"language-json"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"http-basic"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"spark.laravel.com"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"username"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"taylor@example.com"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[a._v('"password"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"your-api-token"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("You may quickly create an "),s("code",[a._v("auth.json")]),a._v(" file via your terminal using the following command. As mentioned previously, you may create an API token via the "),s("a",{attrs:{href:"https://spark.laravel.com/user/api-tokens",target:"_blank",rel:"noopener noreferrer"}},[a._v("Spark dashboard"),s("OutboundLink")],1),a._v(". This token may be used as a substitute for your password when creating a Composer "),s("code",[a._v("auth.json")]),a._v(" file:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("composer")]),a._v(" config http-basic.spark.laravel.com taylor@example.com your-api-token\n")])])]),s("div",{staticClass:"custom-block danger"},[s("p",{staticClass:"custom-block-title"},[a._v("The `auth.json` File")]),a._v(" "),s("p",[a._v("You should not commit your application's "),s("code",[a._v("auth.json")]),a._v(" file into source control.")])]),a._v(" "),s("p",[a._v("Once the package is installed via Composer, run the "),s("code",[a._v("spark:install")]),a._v(" Artisan command:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("php artisan spark:install\n")])])]),s("p",[a._v("Finally, run the "),s("code",[a._v("migrate")]),a._v(" Artisan command:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("php artisan migrate\n")])])]),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[a._v("Stripe Billables")]),a._v(" "),s("p",[a._v("If you are using the Stripe edition of Spark and plan to bill a model other than the "),s("code",[a._v("App\\Models\\User")]),a._v(" model, you should follow "),s("RouterLink",{attrs:{to:"/2.x/spark-stripe/customization.html#migrations"}},[a._v("these instructions")]),a._v(" before running the migration command.")],1)]),a._v(" "),s("p",[a._v("That's it! Next, you may navigate to your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file and begin configuring your Spark installation.")]),a._v(" "),s("h2",{attrs:{id:"authenticating-spark-in-continuous-integration-ci-environments"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#authenticating-spark-in-continuous-integration-ci-environments"}},[a._v("#")]),a._v(" Authenticating Spark in Continuous Integration (CI) Environments")]),a._v(" "),s("p",[a._v("It's not advised to store your "),s("code",[a._v("auth.json")]),a._v(" file inside your project's version control repository. However, there may be times you wish to download Spark inside a CI environment like "),s("a",{attrs:{href:"https://chipperci.com/",target:"_blank",rel:"noopener noreferrer"}},[a._v("Chipper CI"),s("OutboundLink")],1),a._v(". For instance, you may wish to run tests for any custom tools you create. To authenticate Spark in these situations, you can use Composer to set the configuration option inside your CI system's pipeline, injecting environment variables containing the credentials you use to login to the Spark dashboard and a valid "),s("a",{attrs:{href:"https://spark.laravel.com/users/api-tokens",target:"_blank",rel:"noopener noreferrer"}},[a._v("Spark dashboard API token"),s("OutboundLink")],1),a._v(":")]),a._v(" "),s("div",{staticClass:"language-sh extra-class"},[s("pre",{pre:!0,attrs:{class:"language-sh"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("composer")]),a._v(" config http-basic.spark.laravel.com "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("${SPARK_USERNAME}")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("${SPARK_API_TOKEN}")]),a._v("\n")])])])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/13.28105fba.js b/.vuepress/dist/assets/js/32.86d65ba4.js similarity index 99% rename from .vuepress/dist/assets/js/13.28105fba.js rename to .vuepress/dist/assets/js/32.86d65ba4.js index cfe8f26..76e060d 100644 --- a/.vuepress/dist/assets/js/13.28105fba.js +++ b/.vuepress/dist/assets/js/32.86d65ba4.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{405:function(e,r,t){"use strict";t.r(r);var a=t(55),o=Object(a.a)({},(function(){var e=this,r=e.$createElement,t=e._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"introduction"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[e._v("#")]),e._v(" Introduction")]),e._v(" "),t("p"),t("div",{staticClass:"table-of-contents"},[t("ul",[t("li",[t("a",{attrs:{href:"#laravel-spark"}},[e._v("Laravel Spark")])]),t("li",[t("a",{attrs:{href:"#supported-payment-providers"}},[e._v("Supported Payment Providers")]),t("ul",[t("li",[t("a",{attrs:{href:"#paddle"}},[e._v("Paddle")])]),t("li",[t("a",{attrs:{href:"#stripe"}},[e._v("Stripe")])])])]),t("li",[t("a",{attrs:{href:"#frequently-asked-questions"}},[e._v("Frequently Asked Questions")])])])]),t("p"),e._v(" "),t("h2",{attrs:{id:"laravel-spark"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#laravel-spark"}},[e._v("#")]),e._v(" Laravel Spark")]),e._v(" "),t("p",[e._v("Laravel Spark is the perfect starting point for your next big idea. When combined with a Laravel application starter kit like "),t("a",{attrs:{href:"https://jetstream.laravel.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Jetstream"),t("OutboundLink")],1),e._v(" or "),t("a",{attrs:{href:"https://laravel.com/docs/starter-kits",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Breeze"),t("OutboundLink")],1),e._v(", or the frontend of your choice, Spark provides a well-designed billing management panel for your application. Spark, which is built on the power of "),t("a",{attrs:{href:"https://laravel.com/docs/billing",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Cashier"),t("OutboundLink")],1),e._v(", allows your customers to subscribe to monthly or yearly billing plans, manage their payment method, update their subscription plans, and download their receipts all from a self-contained, beautifully designed billing portal.")]),e._v(" "),t("iframe",{attrs:{width:"600",height:"337",src:"https://www.youtube.com/embed/-wAmFagQSzI",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:""}}),e._v(" "),t("h2",{attrs:{id:"supported-payment-providers"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#supported-payment-providers"}},[e._v("#")]),e._v(" Supported Payment Providers")]),e._v(" "),t("p",[e._v("Spark supports two payment providers, and purchasing a Spark license grants you the ability to use either of these payment providers. "),t("strong",[e._v("At this time, it is not possible to implement your own custom payment provider when using Spark.")]),e._v(" We'll provide a brief overview of each provider below.")]),e._v(" "),t("h3",{attrs:{id:"paddle"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#paddle"}},[e._v("#")]),e._v(" Paddle")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Paddle"),t("OutboundLink")],1),e._v(" is a robust billing provider that serves as a merchant of record for your application. Paddle removes the burden of tax compliance from your SaaS business by handling the complexity of gathering and paying your VAT for you. In addition, Paddle provides support for accepting payments from your customers via credit card or PayPal, localized pricing, and hosted invoices.")]),e._v(" "),t("p",[e._v("Spark's Paddle support is provided by the underlying "),t("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Cashier Paddle"),t("OutboundLink")],1),e._v(" library.")]),e._v(" "),t("div",{staticClass:"custom-block warning"},[t("p",{staticClass:"custom-block-title"},[e._v("Paddle Account Approval")]),e._v(" "),t("p",[e._v("Your Paddle account must be approved by Paddle before you can begin using Spark. To apply for an account, please visit the "),t("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Paddle website"),t("OutboundLink")],1),e._v(". "),t("strong",[e._v("While you are developing your application, you may use the "),t("a",{attrs:{href:"https://developer.paddle.com/getting-started/sandbox",target:"_blank",rel:"noopener noreferrer"}},[e._v("Paddle Sandbox"),t("OutboundLink")],1)]),e._v(".")])]),e._v(" "),t("h4",{attrs:{id:"limitations"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#limitations"}},[e._v("#")]),e._v(" Limitations")]),e._v(" "),t("p",[e._v("We have listed some known limitations of using the Paddle payment provider below:")]),e._v(" "),t("ul",[t("li",[e._v("When a recurring coupon is used while subscribing to a plan, the coupon discount will be applied on every billing cycle. However, if the subscription's quantity or plan changes, Paddle will remove the coupon from the subscription.")]),e._v(" "),t("li",[e._v("Because Paddle does not allow plan quantity changes during trial periods, the Paddle edition of Spark does not support requiring a credit card up front when beginning a trial. All trial periods are started without a credit card or payment method provided up front during the user's initial registration process.")])]),e._v(" "),t("h3",{attrs:{id:"stripe"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#stripe"}},[e._v("#")]),e._v(" Stripe")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://stripe.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Stripe"),t("OutboundLink")],1),e._v(" is a global leader in payment infrastructure with direct integration with card networks and banks, a fast-improving platform, and battle-tested reliability. In addition, intelligent optimizations help increase revenue across conversion, prevent fraud, and assist with revenue recovery. Finally, Stripe provides a robust sandbox environment for you to test your application's payment system.")]),e._v(" "),t("p",[e._v("Spark's Stripe support is provided by the underlying "),t("a",{attrs:{href:"https://laravel.com/docs/billing",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Cashier Stripe"),t("OutboundLink")],1),e._v(" library.")]),e._v(" "),t("h4",{attrs:{id:"limitations-2"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#limitations-2"}},[e._v("#")]),e._v(" Limitations")]),e._v(" "),t("p",[e._v("We have listed some known limitations of using the Stripe payment provider below:")]),e._v(" "),t("ul",[t("li",[e._v("The Stripe payment provider does not provide a PayPal integration.")])]),e._v(" "),t("h2",{attrs:{id:"frequently-asked-questions"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#frequently-asked-questions"}},[e._v("#")]),e._v(" Frequently Asked Questions")]),e._v(" "),t("h4",{attrs:{id:"is-it-possible-to-upgrade-an-application-from-spark-classic-to-spark"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#is-it-possible-to-upgrade-an-application-from-spark-classic-to-spark"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Is it possible to upgrade an application from Spark Classic to Spark?")])]),e._v(" "),t("p",[e._v("No. However, we will continue to provide bug fixes and security updates to Spark Classic indefinitely.")]),e._v(" "),t("h4",{attrs:{id:"does-spark-support-any-other-payment-providers"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#does-spark-support-any-other-payment-providers"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Does Spark support any other payment providers?")])]),e._v(" "),t("p",[e._v("No. Spark only supports Stripe and Paddle and it is not possible for developers to customize Spark to accept additional providers. If you need to use another payment provider "),t("strong",[e._v("you should not purchase Laravel Spark")]),e._v(".")]),e._v(" "),t("h4",{attrs:{id:"am-i-required-to-use-tailwind-blade-vue-etc-in-order-to-use-spark"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#am-i-required-to-use-tailwind-blade-vue-etc-in-order-to-use-spark"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Am I required to use Tailwind / Blade / Vue / etc. in order to use Spark?")])]),e._v(" "),t("p",[e._v("No. Spark's billing portal is totally isolated from the rest of your Laravel application and includes its own pre-compiled frontend assets. Your own application may be built using the frontend technologies of your choice.")]),e._v(" "),t("h4",{attrs:{id:"why-are-my-customers-presented-with-a-payment-confirmation-screen"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#why-are-my-customers-presented-with-a-payment-confirmation-screen"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Why are my customers presented with a payment confirmation screen?")])]),e._v(" "),t("p",[e._v("Extra verification is sometimes required in order to confirm and process a payment. When this happens, Paddle or Stripe will present a payment confirmation screen. Payment confirmation screens presented by Paddle, Stripe, or Spark may be tailored to a specific bank or card issuer's payment flow and can include additional card confirmation, a temporary small charge, separate device authentication, or other forms of verification.")])])}),[],!1,null,null,null);r.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[32],{425:function(e,r,t){"use strict";t.r(r);var a=t(55),o=Object(a.a)({},(function(){var e=this,r=e.$createElement,t=e._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"introduction"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[e._v("#")]),e._v(" Introduction")]),e._v(" "),t("p"),t("div",{staticClass:"table-of-contents"},[t("ul",[t("li",[t("a",{attrs:{href:"#laravel-spark"}},[e._v("Laravel Spark")])]),t("li",[t("a",{attrs:{href:"#supported-payment-providers"}},[e._v("Supported Payment Providers")]),t("ul",[t("li",[t("a",{attrs:{href:"#paddle"}},[e._v("Paddle")])]),t("li",[t("a",{attrs:{href:"#stripe"}},[e._v("Stripe")])])])]),t("li",[t("a",{attrs:{href:"#frequently-asked-questions"}},[e._v("Frequently Asked Questions")])])])]),t("p"),e._v(" "),t("h2",{attrs:{id:"laravel-spark"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#laravel-spark"}},[e._v("#")]),e._v(" Laravel Spark")]),e._v(" "),t("p",[e._v("Laravel Spark is the perfect starting point for your next big idea. When combined with a Laravel application starter kit like "),t("a",{attrs:{href:"https://jetstream.laravel.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Jetstream"),t("OutboundLink")],1),e._v(" or "),t("a",{attrs:{href:"https://laravel.com/docs/starter-kits",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Breeze"),t("OutboundLink")],1),e._v(", or the frontend of your choice, Spark provides a well-designed billing management panel for your application. Spark, which is built on the power of "),t("a",{attrs:{href:"https://laravel.com/docs/billing",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Cashier"),t("OutboundLink")],1),e._v(", allows your customers to subscribe to monthly or yearly billing plans, manage their payment method, update their subscription plans, and download their receipts all from a self-contained, beautifully designed billing portal.")]),e._v(" "),t("iframe",{attrs:{width:"600",height:"337",src:"https://www.youtube.com/embed/-wAmFagQSzI",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:""}}),e._v(" "),t("h2",{attrs:{id:"supported-payment-providers"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#supported-payment-providers"}},[e._v("#")]),e._v(" Supported Payment Providers")]),e._v(" "),t("p",[e._v("Spark supports two payment providers, and purchasing a Spark license grants you the ability to use either of these payment providers. "),t("strong",[e._v("At this time, it is not possible to implement your own custom payment provider when using Spark.")]),e._v(" We'll provide a brief overview of each provider below.")]),e._v(" "),t("h3",{attrs:{id:"paddle"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#paddle"}},[e._v("#")]),e._v(" Paddle")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Paddle"),t("OutboundLink")],1),e._v(" is a robust billing provider that serves as a merchant of record for your application. Paddle removes the burden of tax compliance from your SaaS business by handling the complexity of gathering and paying your VAT for you. In addition, Paddle provides support for accepting payments from your customers via credit card or PayPal, localized pricing, and hosted invoices.")]),e._v(" "),t("p",[e._v("Spark's Paddle support is provided by the underlying "),t("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Cashier Paddle"),t("OutboundLink")],1),e._v(" library.")]),e._v(" "),t("div",{staticClass:"custom-block warning"},[t("p",{staticClass:"custom-block-title"},[e._v("Paddle Account Approval")]),e._v(" "),t("p",[e._v("Your Paddle account must be approved by Paddle before you can begin using Spark. To apply for an account, please visit the "),t("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Paddle website"),t("OutboundLink")],1),e._v(". "),t("strong",[e._v("While you are developing your application, you may use the "),t("a",{attrs:{href:"https://developer.paddle.com/getting-started/sandbox",target:"_blank",rel:"noopener noreferrer"}},[e._v("Paddle Sandbox"),t("OutboundLink")],1)]),e._v(".")])]),e._v(" "),t("h4",{attrs:{id:"limitations"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#limitations"}},[e._v("#")]),e._v(" Limitations")]),e._v(" "),t("p",[e._v("We have listed some known limitations of using the Paddle payment provider below:")]),e._v(" "),t("ul",[t("li",[e._v("When a recurring coupon is used while subscribing to a plan, the coupon discount will be applied on every billing cycle. However, if the subscription's quantity or plan changes, Paddle will remove the coupon from the subscription.")]),e._v(" "),t("li",[e._v("Because Paddle does not allow plan quantity changes during trial periods, the Paddle edition of Spark does not support requiring a credit card up front when beginning a trial. All trial periods are started without a credit card or payment method provided up front during the user's initial registration process.")])]),e._v(" "),t("h3",{attrs:{id:"stripe"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#stripe"}},[e._v("#")]),e._v(" Stripe")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://stripe.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("Stripe"),t("OutboundLink")],1),e._v(" is a global leader in payment infrastructure with direct integration with card networks and banks, a fast-improving platform, and battle-tested reliability. In addition, intelligent optimizations help increase revenue across conversion, prevent fraud, and assist with revenue recovery. Finally, Stripe provides a robust sandbox environment for you to test your application's payment system.")]),e._v(" "),t("p",[e._v("Spark's Stripe support is provided by the underlying "),t("a",{attrs:{href:"https://laravel.com/docs/billing",target:"_blank",rel:"noopener noreferrer"}},[e._v("Laravel Cashier Stripe"),t("OutboundLink")],1),e._v(" library.")]),e._v(" "),t("h4",{attrs:{id:"limitations-2"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#limitations-2"}},[e._v("#")]),e._v(" Limitations")]),e._v(" "),t("p",[e._v("We have listed some known limitations of using the Stripe payment provider below:")]),e._v(" "),t("ul",[t("li",[e._v("The Stripe payment provider does not provide a PayPal integration.")])]),e._v(" "),t("h2",{attrs:{id:"frequently-asked-questions"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#frequently-asked-questions"}},[e._v("#")]),e._v(" Frequently Asked Questions")]),e._v(" "),t("h4",{attrs:{id:"is-it-possible-to-upgrade-an-application-from-spark-classic-to-spark"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#is-it-possible-to-upgrade-an-application-from-spark-classic-to-spark"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Is it possible to upgrade an application from Spark Classic to Spark?")])]),e._v(" "),t("p",[e._v("No. However, we will continue to provide bug fixes and security updates to Spark Classic indefinitely.")]),e._v(" "),t("h4",{attrs:{id:"does-spark-support-any-other-payment-providers"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#does-spark-support-any-other-payment-providers"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Does Spark support any other payment providers?")])]),e._v(" "),t("p",[e._v("No. Spark only supports Stripe and Paddle and it is not possible for developers to customize Spark to accept additional providers. If you need to use another payment provider "),t("strong",[e._v("you should not purchase Laravel Spark")]),e._v(".")]),e._v(" "),t("h4",{attrs:{id:"am-i-required-to-use-tailwind-blade-vue-etc-in-order-to-use-spark"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#am-i-required-to-use-tailwind-blade-vue-etc-in-order-to-use-spark"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Am I required to use Tailwind / Blade / Vue / etc. in order to use Spark?")])]),e._v(" "),t("p",[e._v("No. Spark's billing portal is totally isolated from the rest of your Laravel application and includes its own pre-compiled frontend assets. Your own application may be built using the frontend technologies of your choice.")]),e._v(" "),t("h4",{attrs:{id:"why-are-my-customers-presented-with-a-payment-confirmation-screen"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#why-are-my-customers-presented-with-a-payment-confirmation-screen"}},[e._v("#")]),e._v(" "),t("strong",[e._v("Why are my customers presented with a payment confirmation screen?")])]),e._v(" "),t("p",[e._v("Extra verification is sometimes required in order to confirm and process a payment. When this happens, Paddle or Stripe will present a payment confirmation screen. Payment confirmation screens presented by Paddle, Stripe, or Spark may be tailored to a specific bank or card issuer's payment flow and can include additional card confirmation, a temporary small charge, separate device authentication, or other forms of verification.")])])}),[],!1,null,null,null);r.default=o.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/33.e8c3aa03.js b/.vuepress/dist/assets/js/33.07907b79.js similarity index 84% rename from .vuepress/dist/assets/js/33.e8c3aa03.js rename to .vuepress/dist/assets/js/33.07907b79.js index 8ea852b..17bc78a 100644 --- a/.vuepress/dist/assets/js/33.e8c3aa03.js +++ b/.vuepress/dist/assets/js/33.07907b79.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[33],{426:function(t,e,n){"use strict";n.r(e);var s=n(55),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("meta",{attrs:{"http-equiv":"refresh",content:"0;url=/docs/2.x/spark-paddle/configuration.html"}})])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[33],{427:function(t,e,n){"use strict";n.r(e);var s=n(55),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("meta",{attrs:{"http-equiv":"refresh",content:"0;url=/docs/2.x/spark-paddle/configuration.html"}})])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/34.10bc56b7.js b/.vuepress/dist/assets/js/34.faa735ab.js similarity index 99% rename from .vuepress/dist/assets/js/34.10bc56b7.js rename to .vuepress/dist/assets/js/34.faa735ab.js index 6a83b46..d0d6cd2 100644 --- a/.vuepress/dist/assets/js/34.10bc56b7.js +++ b/.vuepress/dist/assets/js/34.faa735ab.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[34],{431:function(a,t,s){"use strict";s.r(t);var e=s(55),n=Object(e.a)({},(function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h1",{attrs:{id:"configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuration"}},[a._v("#")]),a._v(" Configuration")]),a._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#introduction"}},[a._v("Introduction")])]),s("li",[s("a",{attrs:{href:"#paddle-configuration"}},[a._v("Paddle Configuration")]),s("ul",[s("li",[s("a",{attrs:{href:"#environment-variables"}},[a._v("Environment Variables")])]),s("li",[s("a",{attrs:{href:"#paddle-webhooks"}},[a._v("Paddle Webhooks")])])])]),s("li",[s("a",{attrs:{href:"#configuring-billables"}},[a._v("Configuring Billables")]),s("ul",[s("li",[s("a",{attrs:{href:"#billable-slugs"}},[a._v("Billable Slugs")])]),s("li",[s("a",{attrs:{href:"#billable-resolution"}},[a._v("Billable Resolution")])]),s("li",[s("a",{attrs:{href:"#billable-authorization"}},[a._v("Billable Authorization")])]),s("li",[s("a",{attrs:{href:"#billable-email-address"}},[a._v("Billable Email Address")])])])]),s("li",[s("a",{attrs:{href:"#defining-subscription-plans"}},[a._v("Defining Subscription Plans")])]),s("li",[s("a",{attrs:{href:"#accessing-the-billing-portal"}},[a._v("Accessing The Billing Portal")])]),s("li",[s("a",{attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[a._v("Showing A Link To The Terms And Conditions")])])])]),s("p"),a._v(" "),s("h2",{attrs:{id:"introduction"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[a._v("#")]),a._v(" Introduction")]),a._v(" "),s("p",[a._v("In the following documentation, we will discuss how to configure a Laravel Spark installation when using the "),s("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[a._v("Paddle"),s("OutboundLink")],1),a._v(" payment provider. All of Spark's configuration options are housed in your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file.")]),a._v(" "),s("h2",{attrs:{id:"paddle-configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#paddle-configuration"}},[a._v("#")]),a._v(" Paddle Configuration")]),a._v(" "),s("p",[a._v("Of course, to use Paddle as a payment provider for your Laravel Spark application you must have an active "),s("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[a._v("Paddle account"),s("OutboundLink")],1),a._v(". "),s("strong",[a._v("While you are developing your application, you may use the "),s("a",{attrs:{href:"https://developer.paddle.com/getting-started/sandbox",target:"_blank",rel:"noopener noreferrer"}},[a._v("Paddle Sandbox"),s("OutboundLink")],1)]),a._v(".")]),a._v(" "),s("h3",{attrs:{id:"environment-variables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#environment-variables"}},[a._v("#")]),a._v(" Environment Variables")]),a._v(" "),s("p",[a._v("Next, you should configure the application environment variables that will be needed by Spark in order to access your Paddle account. These variables should be placed in your application's "),s("code",[a._v(".env")]),a._v(" environment file.")]),a._v(" "),s("p",[a._v("Of course, you should adjust the variable's values to correspond to your own Paddle account's credentials. In addition, you should set the "),s("code",[a._v("PADDLE_SANDBOX")]),a._v(" variable to "),s("code",[a._v("true")]),a._v(' if you are using Paddle\'s sandbox environment. Your Paddle API credentials and public key are available in your Paddle account dashboard via the "Developer Tools" section\'s "Authentication", "Public Key", and "SDK API" panels:')]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("CASHIER_CURRENCY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("USD\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("CASHIER_CURRENCY_LOCALE")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("en\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_SANDBOX")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("true\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_VENDOR_ID")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("your-paddle-vendor-id\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_VENDOR_AUTH_CODE")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("your-paddle-vendor-auth-code\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_PUBLIC_KEY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"-----BEGIN PUBLIC KEY-----\nMIICIjANBiuqhiiG9w0BAQEFXAOCAg8AMIIjjgKCAraAyj/UyC89sqpOnpEZcM76\nguppK9vfF7balLj87rE9VXq5...EAAQ==\n-----END PUBLIC KEY-----"')]),a._v("\n")])])]),s("div",{staticClass:"custom-block danger"},[s("p",{staticClass:"custom-block-title"},[a._v("Configuring Locales")]),a._v(" "),s("p",[a._v("In order to use locales other than "),s("code",[a._v("en")]),a._v(", ensure the "),s("code",[a._v("ext-intl")]),a._v(" PHP extension is installed and configured on your server.")])]),a._v(" "),s("h3",{attrs:{id:"paddle-webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#paddle-webhooks"}},[a._v("#")]),a._v(" Paddle Webhooks")]),a._v(" "),s("p",[a._v("In addition, your Spark powered application will need to receive webhooks from Paddle in order to keep your application's billing and subscription data in sync with Paddle's. Within your Paddle dashboard's \"Alerts / Webhooks\" management panel, you should configure Paddle to send webhook alerts to your application's "),s("code",[a._v("/spark/webhook")]),a._v(" URI. You should enable webhook alerts for the following events:")]),a._v(" "),s("ul",[s("li",[a._v("Subscription Created")]),a._v(" "),s("li",[a._v("Subscription Updated")]),a._v(" "),s("li",[a._v("Subscription Cancelled")]),a._v(" "),s("li",[a._v("Subscription Payment Success")]),a._v(" "),s("li",[a._v("Subscription Payment Failed")]),a._v(" "),s("li",[a._v("High Risk Transaction Created")]),a._v(" "),s("li",[a._v("High Risk Transaction Updated")])]),a._v(" "),s("h4",{attrs:{id:"webhooks-local-development"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks-local-development"}},[a._v("#")]),a._v(" Webhooks & Local Development")]),a._v(" "),s("p",[a._v("For Paddle to be able to send your application webhooks during local development, you will need to expose your application via a site sharing service such as "),s("a",{attrs:{href:"https://ngrok.io",target:"_blank",rel:"noopener noreferrer"}},[a._v("Ngrok"),s("OutboundLink")],1),a._v(" or "),s("a",{attrs:{href:"https://beyondco.de/docs/expose/introduction",target:"_blank",rel:"noopener noreferrer"}},[a._v("Expose"),s("OutboundLink")],1),a._v(". If you are developing your application locally using "),s("a",{attrs:{href:"http://laravel.com/docs/sail",target:"_blank",rel:"noopener noreferrer"}},[a._v("Laravel Sail"),s("OutboundLink")],1),a._v(", you may use Sail's "),s("a",{attrs:{href:"https://laravel.com/docs/sail#sharing-your-site",target:"_blank",rel:"noopener noreferrer"}},[a._v("site sharing command"),s("OutboundLink")],1),a._v(".")]),a._v(" "),s("h2",{attrs:{id:"configuring-billables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuring-billables"}},[a._v("#")]),a._v(" Configuring Billables")]),a._v(" "),s("p",[a._v("Spark allows you to define the types of billable models that your application will be managing. Most commonly, applications bill individual users for monthly and yearly subscription plans. However, your application may choose to bill some other type of model, such as a team, organization, band, etc.")]),a._v(" "),s("p",[a._v("You may define your billable models within the "),s("code",[a._v("billables")]),a._v(" array of your application's "),s("code",[a._v("spark")]),a._v(" configuration file. By default, this array contains an entry for the "),s("code",[a._v("App\\Models\\User")]),a._v(" model.")]),a._v(" "),s("p",[a._v("Before continuing, you should ensure that the model class that corresponds to your billable model is using the "),s("code",[a._v("Spark\\Billable")]),a._v(" trait:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[a._v("")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("p",[a._v("However, if your application is not billing individual users, you may need to adjust this callback. For example, if your application offers team billing instead of user billing, you might customize the callback like so:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("currentTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("h3",{attrs:{id:"billable-authorization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-authorization"}},[a._v("#")]),a._v(" Billable Authorization")]),a._v(" "),s("p",[a._v("Next, let's examine the authorization callbacks that Spark will use to determine if the currently authenticated user of your application is authorized to view the billing portal for a particular billable model.")]),a._v(" "),s("p",[a._v("When you installed Laravel Spark, an "),s("code",[a._v("App\\Providers\\SparkServiceProvider")]),a._v(" class was created for you. Within this service provider, you will find the authorization callback definition used to determine if a given user is authorized to view the billing portal for the "),s("code",[a._v("App\\Models\\User")]),a._v(" billable class. Of course, if your application is not billing users, you should update the billable class and authorization callback logic to fit your application's needs. By default, Spark will simply verify that the currently authenticated user can only manage its own billing settings:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("User")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&&")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("id")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("==")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("p",[a._v("If the authorization callback returns "),s("code",[a._v("true")]),a._v(", the currently authenticated user will be authorized to view the billing portal and manage the billing settings for the given "),s("code",[a._v("$billable")]),a._v(" model. If the callback returns "),s("code",[a._v("false")]),a._v(", the request to access the billing portal will be denied.")]),a._v(" "),s("p",[a._v("You are free to customize the "),s("code",[a._v("authorize")]),a._v(" callback based on your own application's needs. For example, if your application bills teams instead of individual users, you might update the callback like so:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Team")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&&")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("ownsTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("h3",{attrs:{id:"billable-email-address"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-email-address"}},[a._v("#")]),a._v(" Billable Email Address")]),a._v(" "),s("p",[a._v("By default, Spark will use your billable model's "),s("code",[a._v("email")]),a._v(" attribute as the email address associated with the Paddle customer record it creates for the model. If you would like to specify another attribute that should be used instead, you may define a "),s("code",[a._v("paddleEmail")]),a._v(" method on your billable model:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("/**\n * Get the email address that should be associated with the Paddle customer.\n *\n * @return string\n */")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("public")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[a._v("paddleEmail")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$this")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("email")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("h2",{attrs:{id:"defining-subscription-plans"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#defining-subscription-plans"}},[a._v("#")]),a._v(" Defining Subscription Plans")]),a._v(" "),s("p",[a._v("As we previously discussed, Spark allows you to define the types of billable models that your application will be managing. These billable models are defined within the "),s("code",[a._v("billables")]),a._v(" array of your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file:")]),a._v(" "),s("p",[a._v("Each billable configuration within the "),s("code",[a._v("billables")]),a._v(" array contains a "),s("code",[a._v("plans")]),a._v(" array. Within this array you may configure each of the billing plans offered by your application to that particular billable type. "),s("strong",[a._v("The "),s("code",[a._v("monthly_id")]),a._v(" and "),s("code",[a._v("yearly_id")]),a._v(" identifiers should correspond to the plan identifiers associated with the subscription plan within your Paddle account dashboard:")])]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'billables'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'user'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'model'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'trial_days'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'plans'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'name'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Standard'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'short_description'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'This is a short, human friendly description of the plan.'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'monthly_id'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("env")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'SPARK_STANDARD_MONTHLY_PLAN'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'yearly_id'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("env")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'SPARK_STANDARD_YEARLY_PLAN'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("1001")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'features'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Feature 1'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Feature 2'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Feature 3'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v("\n")])])]),s("p",[a._v("If your subscription plan only offers a monthly billing cycle, you may omit the "),s("code",[a._v("yearly_id")]),a._v(" identifier from your plan configuration. Likewise, if your plan only offers a yearly billing cycle, you may omit the "),s("code",[a._v("monthly_id")]),a._v(" identifier.")]),a._v(" "),s("p",[a._v("In addition, you are free to supply a short description of the plan and a list of features relevant to the plan. This information will be displayed in the Spark billing portal.")]),a._v(" "),s("h2",{attrs:{id:"accessing-the-billing-portal"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#accessing-the-billing-portal"}},[a._v("#")]),a._v(" Accessing The Billing Portal")]),a._v(" "),s("p",[a._v("Once you have configured your Spark installation, you may access your application's billing portal at the "),s("code",[a._v("/billing")]),a._v(" URI. So, if your application is being served on "),s("code",[a._v("localhost")]),a._v(", you may access your application's billing portal at "),s("code",[a._v("http://localhost/billing")]),a._v(".")]),a._v(" "),s("p",[a._v("Of course, you may link to the billing portal from your application's dashboard however you see fit:")]),a._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("a")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("href")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v('"')]),a._v("/billing"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("\n Manage Subscription\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n")])])]),s("h4",{attrs:{id:"billing-portal-multiple-billables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billing-portal-multiple-billables"}},[a._v("#")]),a._v(" Billing Portal & Multiple Billables")]),a._v(" "),s("p",[a._v("If your application is billing more than one type of billable, you should add the billable type's "),s("a",{attrs:{href:"#billable-slugs"}},[a._v("slug")]),a._v(" to the "),s("code",[a._v("/billing")]),a._v(" URI. For example, if you have configured a "),s("code",[a._v("team")]),a._v(" billable type in addition to your "),s("code",[a._v("user")]),a._v(" billable type, you may access the billing portal for teams by navigating to "),s("code",[a._v("http://localhost/billing/team")]),a._v(". However, this typically should not be necessary because most applications will only ever bill one type of model.")]),a._v(" "),s("h2",{attrs:{id:"showing-a-link-to-the-terms-and-conditions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[a._v("#")]),a._v(" Showing A Link To The Terms And Conditions")]),a._v(" "),s("p",[a._v("Many applications display billing terms and conditions during checkout. Spark allows you to easily do the same within your application's billing portal. To get started, add a "),s("code",[a._v("terms_url")]),a._v(" configuration value in your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'terms_url'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'/terms'")]),a._v("\n")])])]),s("p",[a._v("Once added, Spark will display a link pointing to "),s("code",[a._v("/terms")]),a._v(" in the billing portal.")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[34],{426:function(a,t,s){"use strict";s.r(t);var e=s(55),n=Object(e.a)({},(function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h1",{attrs:{id:"configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuration"}},[a._v("#")]),a._v(" Configuration")]),a._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#introduction"}},[a._v("Introduction")])]),s("li",[s("a",{attrs:{href:"#paddle-configuration"}},[a._v("Paddle Configuration")]),s("ul",[s("li",[s("a",{attrs:{href:"#environment-variables"}},[a._v("Environment Variables")])]),s("li",[s("a",{attrs:{href:"#paddle-webhooks"}},[a._v("Paddle Webhooks")])])])]),s("li",[s("a",{attrs:{href:"#configuring-billables"}},[a._v("Configuring Billables")]),s("ul",[s("li",[s("a",{attrs:{href:"#billable-slugs"}},[a._v("Billable Slugs")])]),s("li",[s("a",{attrs:{href:"#billable-resolution"}},[a._v("Billable Resolution")])]),s("li",[s("a",{attrs:{href:"#billable-authorization"}},[a._v("Billable Authorization")])]),s("li",[s("a",{attrs:{href:"#billable-email-address"}},[a._v("Billable Email Address")])])])]),s("li",[s("a",{attrs:{href:"#defining-subscription-plans"}},[a._v("Defining Subscription Plans")])]),s("li",[s("a",{attrs:{href:"#accessing-the-billing-portal"}},[a._v("Accessing The Billing Portal")])]),s("li",[s("a",{attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[a._v("Showing A Link To The Terms And Conditions")])])])]),s("p"),a._v(" "),s("h2",{attrs:{id:"introduction"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[a._v("#")]),a._v(" Introduction")]),a._v(" "),s("p",[a._v("In the following documentation, we will discuss how to configure a Laravel Spark installation when using the "),s("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[a._v("Paddle"),s("OutboundLink")],1),a._v(" payment provider. All of Spark's configuration options are housed in your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file.")]),a._v(" "),s("h2",{attrs:{id:"paddle-configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#paddle-configuration"}},[a._v("#")]),a._v(" Paddle Configuration")]),a._v(" "),s("p",[a._v("Of course, to use Paddle as a payment provider for your Laravel Spark application you must have an active "),s("a",{attrs:{href:"https://paddle.com",target:"_blank",rel:"noopener noreferrer"}},[a._v("Paddle account"),s("OutboundLink")],1),a._v(". "),s("strong",[a._v("While you are developing your application, you may use the "),s("a",{attrs:{href:"https://developer.paddle.com/getting-started/sandbox",target:"_blank",rel:"noopener noreferrer"}},[a._v("Paddle Sandbox"),s("OutboundLink")],1)]),a._v(".")]),a._v(" "),s("h3",{attrs:{id:"environment-variables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#environment-variables"}},[a._v("#")]),a._v(" Environment Variables")]),a._v(" "),s("p",[a._v("Next, you should configure the application environment variables that will be needed by Spark in order to access your Paddle account. These variables should be placed in your application's "),s("code",[a._v(".env")]),a._v(" environment file.")]),a._v(" "),s("p",[a._v("Of course, you should adjust the variable's values to correspond to your own Paddle account's credentials. In addition, you should set the "),s("code",[a._v("PADDLE_SANDBOX")]),a._v(" variable to "),s("code",[a._v("true")]),a._v(' if you are using Paddle\'s sandbox environment. Your Paddle API credentials and public key are available in your Paddle account dashboard via the "Developer Tools" section\'s "Authentication", "Public Key", and "SDK API" panels:')]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("CASHIER_CURRENCY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("USD\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("CASHIER_CURRENCY_LOCALE")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("en\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_SANDBOX")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("true\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_VENDOR_ID")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("your-paddle-vendor-id\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_VENDOR_AUTH_CODE")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("your-paddle-vendor-auth-code\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("PADDLE_PUBLIC_KEY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"-----BEGIN PUBLIC KEY-----\nMIICIjANBiuqhiiG9w0BAQEFXAOCAg8AMIIjjgKCAraAyj/UyC89sqpOnpEZcM76\nguppK9vfF7balLj87rE9VXq5...EAAQ==\n-----END PUBLIC KEY-----"')]),a._v("\n")])])]),s("div",{staticClass:"custom-block danger"},[s("p",{staticClass:"custom-block-title"},[a._v("Configuring Locales")]),a._v(" "),s("p",[a._v("In order to use locales other than "),s("code",[a._v("en")]),a._v(", ensure the "),s("code",[a._v("ext-intl")]),a._v(" PHP extension is installed and configured on your server.")])]),a._v(" "),s("h3",{attrs:{id:"paddle-webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#paddle-webhooks"}},[a._v("#")]),a._v(" Paddle Webhooks")]),a._v(" "),s("p",[a._v("In addition, your Spark powered application will need to receive webhooks from Paddle in order to keep your application's billing and subscription data in sync with Paddle's. Within your Paddle dashboard's \"Alerts / Webhooks\" management panel, you should configure Paddle to send webhook alerts to your application's "),s("code",[a._v("/spark/webhook")]),a._v(" URI. You should enable webhook alerts for the following events:")]),a._v(" "),s("ul",[s("li",[a._v("Subscription Created")]),a._v(" "),s("li",[a._v("Subscription Updated")]),a._v(" "),s("li",[a._v("Subscription Cancelled")]),a._v(" "),s("li",[a._v("Subscription Payment Success")]),a._v(" "),s("li",[a._v("Subscription Payment Failed")]),a._v(" "),s("li",[a._v("High Risk Transaction Created")]),a._v(" "),s("li",[a._v("High Risk Transaction Updated")])]),a._v(" "),s("h4",{attrs:{id:"webhooks-local-development"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks-local-development"}},[a._v("#")]),a._v(" Webhooks & Local Development")]),a._v(" "),s("p",[a._v("For Paddle to be able to send your application webhooks during local development, you will need to expose your application via a site sharing service such as "),s("a",{attrs:{href:"https://ngrok.io",target:"_blank",rel:"noopener noreferrer"}},[a._v("Ngrok"),s("OutboundLink")],1),a._v(" or "),s("a",{attrs:{href:"https://beyondco.de/docs/expose/introduction",target:"_blank",rel:"noopener noreferrer"}},[a._v("Expose"),s("OutboundLink")],1),a._v(". If you are developing your application locally using "),s("a",{attrs:{href:"http://laravel.com/docs/sail",target:"_blank",rel:"noopener noreferrer"}},[a._v("Laravel Sail"),s("OutboundLink")],1),a._v(", you may use Sail's "),s("a",{attrs:{href:"https://laravel.com/docs/sail#sharing-your-site",target:"_blank",rel:"noopener noreferrer"}},[a._v("site sharing command"),s("OutboundLink")],1),a._v(".")]),a._v(" "),s("h2",{attrs:{id:"configuring-billables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuring-billables"}},[a._v("#")]),a._v(" Configuring Billables")]),a._v(" "),s("p",[a._v("Spark allows you to define the types of billable models that your application will be managing. Most commonly, applications bill individual users for monthly and yearly subscription plans. However, your application may choose to bill some other type of model, such as a team, organization, band, etc.")]),a._v(" "),s("p",[a._v("You may define your billable models within the "),s("code",[a._v("billables")]),a._v(" array of your application's "),s("code",[a._v("spark")]),a._v(" configuration file. By default, this array contains an entry for the "),s("code",[a._v("App\\Models\\User")]),a._v(" model.")]),a._v(" "),s("p",[a._v("Before continuing, you should ensure that the model class that corresponds to your billable model is using the "),s("code",[a._v("Spark\\Billable")]),a._v(" trait:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[a._v("")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("p",[a._v("However, if your application is not billing individual users, you may need to adjust this callback. For example, if your application offers team billing instead of user billing, you might customize the callback like so:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("currentTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("h3",{attrs:{id:"billable-authorization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-authorization"}},[a._v("#")]),a._v(" Billable Authorization")]),a._v(" "),s("p",[a._v("Next, let's examine the authorization callbacks that Spark will use to determine if the currently authenticated user of your application is authorized to view the billing portal for a particular billable model.")]),a._v(" "),s("p",[a._v("When you installed Laravel Spark, an "),s("code",[a._v("App\\Providers\\SparkServiceProvider")]),a._v(" class was created for you. Within this service provider, you will find the authorization callback definition used to determine if a given user is authorized to view the billing portal for the "),s("code",[a._v("App\\Models\\User")]),a._v(" billable class. Of course, if your application is not billing users, you should update the billable class and authorization callback logic to fit your application's needs. By default, Spark will simply verify that the currently authenticated user can only manage its own billing settings:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("User")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&&")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("id")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("==")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("p",[a._v("If the authorization callback returns "),s("code",[a._v("true")]),a._v(", the currently authenticated user will be authorized to view the billing portal and manage the billing settings for the given "),s("code",[a._v("$billable")]),a._v(" model. If the callback returns "),s("code",[a._v("false")]),a._v(", the request to access the billing portal will be denied.")]),a._v(" "),s("p",[a._v("You are free to customize the "),s("code",[a._v("authorize")]),a._v(" callback based on your own application's needs. For example, if your application bills teams instead of individual users, you might update the callback like so:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Team")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[a._v("Request")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&&")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("ownsTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n")])])]),s("h3",{attrs:{id:"billable-email-address"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-email-address"}},[a._v("#")]),a._v(" Billable Email Address")]),a._v(" "),s("p",[a._v("By default, Spark will use your billable model's "),s("code",[a._v("email")]),a._v(" attribute as the email address associated with the Paddle customer record it creates for the model. If you would like to specify another attribute that should be used instead, you may define a "),s("code",[a._v("paddleEmail")]),a._v(" method on your billable model:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("/**\n * Get the email address that should be associated with the Paddle customer.\n *\n * @return string\n */")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("public")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[a._v("paddleEmail")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$this")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[a._v("email")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("h2",{attrs:{id:"defining-subscription-plans"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#defining-subscription-plans"}},[a._v("#")]),a._v(" Defining Subscription Plans")]),a._v(" "),s("p",[a._v("As we previously discussed, Spark allows you to define the types of billable models that your application will be managing. These billable models are defined within the "),s("code",[a._v("billables")]),a._v(" array of your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file:")]),a._v(" "),s("p",[a._v("Each billable configuration within the "),s("code",[a._v("billables")]),a._v(" array contains a "),s("code",[a._v("plans")]),a._v(" array. Within this array you may configure each of the billing plans offered by your application to that particular billable type. "),s("strong",[a._v("The "),s("code",[a._v("monthly_id")]),a._v(" and "),s("code",[a._v("yearly_id")]),a._v(" identifiers should correspond to the plan identifiers associated with the subscription plan within your Paddle account dashboard:")])]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("use")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[a._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'billables'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'user'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'model'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[a._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'trial_days'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'plans'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'name'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Standard'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'short_description'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'This is a short, human friendly description of the plan.'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'monthly_id'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("env")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'SPARK_STANDARD_MONTHLY_PLAN'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'yearly_id'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("env")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'SPARK_STANDARD_YEARLY_PLAN'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("1001")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'features'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Feature 1'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Feature 2'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'Feature 3'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v("\n")])])]),s("p",[a._v("If your subscription plan only offers a monthly billing cycle, you may omit the "),s("code",[a._v("yearly_id")]),a._v(" identifier from your plan configuration. Likewise, if your plan only offers a yearly billing cycle, you may omit the "),s("code",[a._v("monthly_id")]),a._v(" identifier.")]),a._v(" "),s("p",[a._v("In addition, you are free to supply a short description of the plan and a list of features relevant to the plan. This information will be displayed in the Spark billing portal.")]),a._v(" "),s("h2",{attrs:{id:"accessing-the-billing-portal"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#accessing-the-billing-portal"}},[a._v("#")]),a._v(" Accessing The Billing Portal")]),a._v(" "),s("p",[a._v("Once you have configured your Spark installation, you may access your application's billing portal at the "),s("code",[a._v("/billing")]),a._v(" URI. So, if your application is being served on "),s("code",[a._v("localhost")]),a._v(", you may access your application's billing portal at "),s("code",[a._v("http://localhost/billing")]),a._v(".")]),a._v(" "),s("p",[a._v("Of course, you may link to the billing portal from your application's dashboard however you see fit:")]),a._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("a")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("href")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v('"')]),a._v("/billing"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("\n Manage Subscription\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n")])])]),s("h4",{attrs:{id:"billing-portal-multiple-billables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billing-portal-multiple-billables"}},[a._v("#")]),a._v(" Billing Portal & Multiple Billables")]),a._v(" "),s("p",[a._v("If your application is billing more than one type of billable, you should add the billable type's "),s("a",{attrs:{href:"#billable-slugs"}},[a._v("slug")]),a._v(" to the "),s("code",[a._v("/billing")]),a._v(" URI. For example, if you have configured a "),s("code",[a._v("team")]),a._v(" billable type in addition to your "),s("code",[a._v("user")]),a._v(" billable type, you may access the billing portal for teams by navigating to "),s("code",[a._v("http://localhost/billing/team")]),a._v(". However, this typically should not be necessary because most applications will only ever bill one type of model.")]),a._v(" "),s("h2",{attrs:{id:"showing-a-link-to-the-terms-and-conditions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[a._v("#")]),a._v(" Showing A Link To The Terms And Conditions")]),a._v(" "),s("p",[a._v("Many applications display billing terms and conditions during checkout. Spark allows you to easily do the same within your application's billing portal. To get started, add a "),s("code",[a._v("terms_url")]),a._v(" configuration value in your application's "),s("code",[a._v("config/spark.php")]),a._v(" configuration file:")]),a._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'terms_url'")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=>")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[a._v("'/terms'")]),a._v("\n")])])]),s("p",[a._v("Once added, Spark will display a link pointing to "),s("code",[a._v("/terms")]),a._v(" in the billing portal.")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/17.b8ed5059.js b/.vuepress/dist/assets/js/36.b4f36b7c.js similarity index 99% rename from .vuepress/dist/assets/js/17.b8ed5059.js rename to .vuepress/dist/assets/js/36.b4f36b7c.js index a40fea8..b45d186 100644 --- a/.vuepress/dist/assets/js/17.b8ed5059.js +++ b/.vuepress/dist/assets/js/36.b4f36b7c.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{408:function(t,a,s){"use strict";s.r(a);var e=s(55),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"customization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#customization"}},[t._v("#")]),t._v(" Customization")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#branding"}},[t._v("Branding")]),s("ul",[s("li",[s("a",{attrs:{href:"#brand-logo"}},[t._v("Brand Logo")])]),s("li",[s("a",{attrs:{href:"#brand-color"}},[t._v("Brand Color")])]),s("li",[s("a",{attrs:{href:"#font"}},[t._v("Font")])])])]),s("li",[s("a",{attrs:{href:"#localization"}},[t._v("Localization")])]),s("li",[s("a",{attrs:{href:"#webhooks"}},[t._v("Webhooks")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"branding"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#branding"}},[t._v("#")]),t._v(" Branding")]),t._v(" "),s("p",[t._v("Although Spark's billing portal is intended to be an isolated part of your application that is entirely managed by Spark, you can make some small customizations to the branding logo and color used by Spark.")]),t._v(" "),s("h3",{attrs:{id:"brand-logo"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#brand-logo"}},[t._v("#")]),t._v(" Brand Logo")]),t._v(" "),s("p",[t._v("To customize the logo used at the top left of the Spark billing portal, you may specify a configuration value for the "),s("code",[t._v("brand.logo")]),t._v(" configuration item within your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file. This configuration value should contain an absolute path to the SVG file of the logo you would like to use:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'brand'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'logo'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("realpath")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("__DIR__")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/../public/img/logo.svg'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("SVG Sizing")]),t._v(" "),s("p",[t._v("You may need to adjust the size and width of your SVG logo by modifying its width in the SVG file itself.")])]),t._v(" "),s("h3",{attrs:{id:"brand-color"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#brand-color"}},[t._v("#")]),t._v(" Brand Color")]),t._v(" "),s("p",[t._v("To customize the color used as the background color of the button elements within the Spark billing portal, you may specify a value for the "),s("code",[t._v("brand.color")]),t._v(" configuration item within your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file. This configuration value should be a valid hex code or correspond to a background color offered by the "),s("a",{attrs:{href:"https://tailwindcss.com/docs/customizing-colors",target:"_blank",rel:"noopener noreferrer"}},[t._v("Tailwind CSS framework"),s("OutboundLink")],1),t._v(":")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'brand'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'bg-indigo-600'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Or...")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'#c5b358'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("h3",{attrs:{id:"font"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#font"}},[t._v("#")]),t._v(" Font")]),t._v(" "),s("p",[t._v("To customize the font used by the Spark billing portal, you should export Spark's views using the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-views\n")])])]),s("p",[t._v("Next, within the "),s("code",[t._v("resources/views/vendor/spark/app.blade.php")]),t._v(" template, you may define your own "),s("code",[t._v("font-sans")]),t._v(" CSS class at the bottom of the templates "),s("code",[t._v("head")]),t._v(" section:")]),t._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("head")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("\x3c!-- ...... --\x3e")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("style")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token style"}},[s("span",{pre:!0,attrs:{class:"token language-css"}},[t._v("\n "),s("span",{pre:!0,attrs:{class:"token selector"}},[t._v(".font-sans")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("font-family")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Your Custom Font'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n ")])]),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("h2",{attrs:{id:"localization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#localization"}},[t._v("#")]),t._v(" Localization")]),t._v(" "),s("p",[t._v("You may localize / translate all of the text within the Spark billing portal. To publish the Spark localization file, you may use the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-lang\n")])])]),s("p",[t._v("This command will publish a "),s("code",[t._v("resources/lang/spark/en.json")]),t._v(" file containing translation keys and values for the English language. You may copy this file and translate it to the language of your choice. For more information on how to use Laravel's translation features, please consult the "),s("a",{attrs:{href:"https://laravel.com/docs/localization#using-translation-strings-as-keys",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel localization documentation"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks"}},[t._v("#")]),t._v(" Webhooks")]),t._v(" "),s("p",[t._v("Spark and Cashier automatically handles subscription cancellation on failed charges and other common Paddle webhooks, but if you have additional webhook events you would like to handle, you should extend Spark's "),s("code",[t._v("WebhookController")]),t._v(".")]),t._v(" "),s("p",[t._v("Your controller's method names should correspond to Cashier's controller method conventions. Specifically, methods should be prefixed with "),s("code",[t._v("handle")]),t._v(' and the "camel case" name of the webhook you wish to handle. For example, if you wish to handle the '),s("code",[t._v("payment_succeeded")]),t._v(" webhook, you should add a "),s("code",[t._v("handlePaymentSucceeded")]),t._v(" method to the controller:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[t._v("")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'logo'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("realpath")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("__DIR__")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/../public/img/logo.svg'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("SVG Sizing")]),t._v(" "),s("p",[t._v("You may need to adjust the size and width of your SVG logo by modifying its width in the SVG file itself.")])]),t._v(" "),s("h3",{attrs:{id:"brand-color"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#brand-color"}},[t._v("#")]),t._v(" Brand Color")]),t._v(" "),s("p",[t._v("To customize the color used as the background color of the button elements within the Spark billing portal, you may specify a value for the "),s("code",[t._v("brand.color")]),t._v(" configuration item within your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file. This configuration value should be a valid hex code or correspond to a background color offered by the "),s("a",{attrs:{href:"https://tailwindcss.com/docs/customizing-colors",target:"_blank",rel:"noopener noreferrer"}},[t._v("Tailwind CSS framework"),s("OutboundLink")],1),t._v(":")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'brand'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'bg-indigo-600'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Or...")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'#c5b358'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("h3",{attrs:{id:"font"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#font"}},[t._v("#")]),t._v(" Font")]),t._v(" "),s("p",[t._v("To customize the font used by the Spark billing portal, you should export Spark's views using the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-views\n")])])]),s("p",[t._v("Next, within the "),s("code",[t._v("resources/views/vendor/spark/app.blade.php")]),t._v(" template, you may define your own "),s("code",[t._v("font-sans")]),t._v(" CSS class at the bottom of the templates "),s("code",[t._v("head")]),t._v(" section:")]),t._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("head")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("\x3c!-- ...... --\x3e")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("style")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token style"}},[s("span",{pre:!0,attrs:{class:"token language-css"}},[t._v("\n "),s("span",{pre:!0,attrs:{class:"token selector"}},[t._v(".font-sans")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("font-family")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Your Custom Font'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n ")])]),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("h2",{attrs:{id:"localization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#localization"}},[t._v("#")]),t._v(" Localization")]),t._v(" "),s("p",[t._v("You may localize / translate all of the text within the Spark billing portal. To publish the Spark localization file, you may use the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-lang\n")])])]),s("p",[t._v("This command will publish a "),s("code",[t._v("resources/lang/spark/en.json")]),t._v(" file containing translation keys and values for the English language. You may copy this file and translate it to the language of your choice. For more information on how to use Laravel's translation features, please consult the "),s("a",{attrs:{href:"https://laravel.com/docs/localization#using-translation-strings-as-keys",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel localization documentation"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks"}},[t._v("#")]),t._v(" Webhooks")]),t._v(" "),s("p",[t._v("Spark and Cashier automatically handles subscription cancellation on failed charges and other common Paddle webhooks, but if you have additional webhook events you would like to handle, you should extend Spark's "),s("code",[t._v("WebhookController")]),t._v(".")]),t._v(" "),s("p",[t._v("Your controller's method names should correspond to Cashier's controller method conventions. Specifically, methods should be prefixed with "),s("code",[t._v("handle")]),t._v(' and the "camel case" name of the webhook you wish to handle. For example, if you wish to handle the '),s("code",[t._v("payment_succeeded")]),t._v(" webhook, you should add a "),s("code",[t._v("handlePaymentSucceeded")]),t._v(" method to the controller:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[t._v("")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("VerifyBillableIsSubscribed")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Once the middleware has been registered, you may attach it to any of your application's route definitions:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Route")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("post")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/projects'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ProjectController")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'store'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("middleware")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'auth'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("If the user has an active subscription, the request will continue to execute normally. However, if the user does not have an active subscription, they will be redirected to your application's Spark billing portal. If the request is an XHR request, a response with a 402 HTTP status code will be returned to the client.")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("Manually Inspecting Subscription States")]),t._v(" "),a("p",[t._v("Of course, you may always manually inspect a billable model's subscription status using the "),a("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),a("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan.")])]),t._v(" "),a("h4",{attrs:{id:"multiple-billables"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#multiple-billables"}},[t._v("#")]),t._v(" Multiple Billables")]),t._v(" "),a("p",[t._v("If your application has more than one configured billable model, you may pass the "),a("RouterLink",{attrs:{to:"/2.x/spark-paddle/configuration.html#billable-slugs"}},[t._v("billable slug")]),t._v(" to the middleware to instruct Spark which billable model configuration to use when verifying the subscription. However, this typically should not be necessary because most applications will only ever bill one type of model:")],1),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Route")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("post")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/projects'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ProjectController")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'store'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("middleware")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'auth'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed:team'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[38],{431:function(t,s,a){"use strict";a.r(s);var e=a(55),n=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"middleware"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#middleware"}},[t._v("#")]),t._v(" Middleware")]),t._v(" "),a("p"),a("div",{staticClass:"table-of-contents"},[a("ul")]),a("p"),t._v(" "),a("p",[t._v("When building a subscription based application, you will commonly need to restrict access to certain routes to users that have an active subscription. For example, you may not want to let a user create a project if they are not subscribed to a billing plan. For that reason, Spark provides a convenient subscription verification "),a("a",{attrs:{href:"https://laravel.com/docs/middleware",target:"_blank",rel:"noopener noreferrer"}},[t._v("middleware"),a("OutboundLink")],1),t._v(" that you may register with your application.")]),t._v(" "),a("p",[t._v("To get started, register Spark's subscription verification middleware in your HTTP kernel's "),a("code",[t._v("$routeMiddleware")]),t._v(" array. Your application's HTTP kernel is typically located at "),a("code",[t._v("app/Http/Kernel.php")]),t._v(":")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Middleware"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("VerifyBillableIsSubscribed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("protected")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$routeMiddleware")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("VerifyBillableIsSubscribed")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Once the middleware has been registered, you may attach it to any of your application's route definitions:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Route")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("post")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/projects'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ProjectController")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'store'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("middleware")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'auth'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("If the user has an active subscription, the request will continue to execute normally. However, if the user does not have an active subscription, they will be redirected to your application's Spark billing portal. If the request is an XHR request, a response with a 402 HTTP status code will be returned to the client.")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("Manually Inspecting Subscription States")]),t._v(" "),a("p",[t._v("Of course, you may always manually inspect a billable model's subscription status using the "),a("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),a("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan.")])]),t._v(" "),a("h4",{attrs:{id:"multiple-billables"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#multiple-billables"}},[t._v("#")]),t._v(" Multiple Billables")]),t._v(" "),a("p",[t._v("If your application has more than one configured billable model, you may pass the "),a("RouterLink",{attrs:{to:"/2.x/spark-paddle/configuration.html#billable-slugs"}},[t._v("billable slug")]),t._v(" to the middleware to instruct Spark which billable model configuration to use when verifying the subscription. However, this typically should not be necessary because most applications will only ever bill one type of model:")],1),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Route")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("post")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/projects'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ProjectController")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'store'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("middleware")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'auth'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed:team'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/20.60dbd01c.js b/.vuepress/dist/assets/js/39.5695320f.js similarity index 99% rename from .vuepress/dist/assets/js/20.60dbd01c.js rename to .vuepress/dist/assets/js/39.5695320f.js index 0adf6ff..90a2678 100644 --- a/.vuepress/dist/assets/js/20.60dbd01c.js +++ b/.vuepress/dist/assets/js/39.5695320f.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{414:function(t,s,a){"use strict";a.r(s);var n=a(55),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"testing"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#testing"}},[t._v("#")]),t._v(" Testing")]),t._v(" "),a("p"),a("div",{staticClass:"table-of-contents"},[a("ul",[a("li",[a("a",{attrs:{href:"#factories"}},[t._v("Factories")])])])]),a("p"),t._v(" "),a("h2",{attrs:{id:"factories"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#factories"}},[t._v("#")]),t._v(" Factories")]),t._v(" "),a("p",[t._v('While developing your application, you will likely want to "stub" a subscription record in your application\'s database so that calls to the '),a("code",[t._v("$billable->subscribed()")]),t._v(" method return "),a("code",[t._v("true")]),t._v(".")]),t._v(" "),a("p",[t._v('To accomplish this, you may add a "state" method to your billable model\'s '),a("a",{attrs:{href:"https://laravel.com/docs/database-testing#defining-model-factories",target:"_blank",rel:"noopener noreferrer"}},[t._v("factory class"),a("OutboundLink")],1),t._v(". Typically, this will be your application's "),a("code",[t._v("UserFactory")]),t._v(" class. Below you will find an example state method implementation; however, you are free to adjust this to your application's own needs:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Indicate that the user should have a subscription plan.\n *\n * @param int $planId\n * @return \\Illuminate\\Database\\Eloquent\\Factories\\Factory\n */")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$this")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("afterCreating")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("optional")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token property"}},[t._v("customer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("update")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscriptions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'default'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paddle_id'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("random_int")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paddle_status'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'active'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paddle_plan'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'quantity'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paused_from'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Once you have define the state method, you may use it when creating models via your factory:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("factory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// true")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[39],{433:function(t,s,a){"use strict";a.r(s);var n=a(55),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"testing"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#testing"}},[t._v("#")]),t._v(" Testing")]),t._v(" "),a("p"),a("div",{staticClass:"table-of-contents"},[a("ul",[a("li",[a("a",{attrs:{href:"#factories"}},[t._v("Factories")])])])]),a("p"),t._v(" "),a("h2",{attrs:{id:"factories"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#factories"}},[t._v("#")]),t._v(" Factories")]),t._v(" "),a("p",[t._v('While developing your application, you will likely want to "stub" a subscription record in your application\'s database so that calls to the '),a("code",[t._v("$billable->subscribed()")]),t._v(" method return "),a("code",[t._v("true")]),t._v(".")]),t._v(" "),a("p",[t._v('To accomplish this, you may add a "state" method to your billable model\'s '),a("a",{attrs:{href:"https://laravel.com/docs/database-testing#defining-model-factories",target:"_blank",rel:"noopener noreferrer"}},[t._v("factory class"),a("OutboundLink")],1),t._v(". Typically, this will be your application's "),a("code",[t._v("UserFactory")]),t._v(" class. Below you will find an example state method implementation; however, you are free to adjust this to your application's own needs:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Indicate that the user should have a subscription plan.\n *\n * @param int $planId\n * @return \\Illuminate\\Database\\Eloquent\\Factories\\Factory\n */")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$this")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("afterCreating")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("optional")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token property"}},[t._v("customer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("update")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscriptions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'default'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paddle_id'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("random_int")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paddle_status'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'active'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paddle_plan'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'quantity'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'paused_from'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Once you have define the state method, you may use it when creating models via your factory:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("factory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// true")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/4.575bc5ce.js b/.vuepress/dist/assets/js/4.5f6bfe57.js similarity index 67% rename from .vuepress/dist/assets/js/4.575bc5ce.js rename to .vuepress/dist/assets/js/4.5f6bfe57.js index 697f6ab..1232569 100644 --- a/.vuepress/dist/assets/js/4.575bc5ce.js +++ b/.vuepress/dist/assets/js/4.5f6bfe57.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{373:function(t,e,a){},400:function(t,e,a){"use strict";a(373)},404:function(t,e,a){"use strict";a.r(e);var n={name:"CodeBlock",props:{title:{type:String,required:!0},active:{type:Boolean,default:!1}},mounted:function(){this.$parent&&this.$parent.loadTabs&&this.$parent.loadTabs()}},i=(a(400),a(55)),s=Object(i.a)(n,(function(){var t=this.$createElement;return(this._self._c||t)("div",{staticClass:"theme-code-block",class:{"theme-code-block__active":this.active}},[this._t("default")],2)}),[],!1,null,"759a7d02",null);e.default=s.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{372:function(t,e,a){},399:function(t,e,a){"use strict";a(372)},403:function(t,e,a){"use strict";a.r(e);var n={name:"CodeBlock",props:{title:{type:String,required:!0},active:{type:Boolean,default:!1}},mounted:function(){this.$parent&&this.$parent.loadTabs&&this.$parent.loadTabs()}},i=(a(399),a(55)),s=Object(i.a)(n,(function(){var t=this.$createElement;return(this._self._c||t)("div",{staticClass:"theme-code-block",class:{"theme-code-block__active":this.active}},[this._t("default")],2)}),[],!1,null,"759a7d02",null);e.default=s.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/40.118df548.js b/.vuepress/dist/assets/js/40.118df548.js deleted file mode 100644 index f55a04f..0000000 --- a/.vuepress/dist/assets/js/40.118df548.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[40],{435:function(a,e,r){"use strict";r.r(e);var t=r(55),s=Object(t.a)({},(function(){var a=this,e=a.$createElement,r=a._self._c||e;return r("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[r("h1",{attrs:{id:"upgrade"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#upgrade"}},[a._v("#")]),a._v(" Upgrade")]),a._v(" "),r("p"),r("div",{staticClass:"table-of-contents"},[r("ul",[r("li",[r("a",{attrs:{href:"#upgrading-to-spark-paddle-v2-0-from-v1-x"}},[a._v("Upgrading to Spark-Paddle v2.0 From v1.x")]),r("ul",[r("li",[r("a",{attrs:{href:"#minimum-versions"}},[a._v("Minimum Versions")])])])])])]),r("p"),a._v(" "),r("h2",{attrs:{id:"upgrading-to-spark-paddle-v2-0-from-v1-x"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#upgrading-to-spark-paddle-v2-0-from-v1-x"}},[a._v("#")]),a._v(" Upgrading to Spark-Paddle v2.0 From v1.x")]),a._v(" "),r("p",[a._v("No major changes were made to Spark Paddle v2.")]),a._v(" "),r("h3",{attrs:{id:"minimum-versions"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#minimum-versions"}},[a._v("#")]),a._v(" Minimum Versions")]),a._v(" "),r("p",[a._v("The following required dependency versions have been updated:")]),a._v(" "),r("ul",[r("li",[a._v("The minimum Laravel version is now v9.0")]),a._v(" "),r("li",[a._v("The minimum PHP version is now v8.0")])])])}),[],!1,null,null,null);e.default=s.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/40.a764658c.js b/.vuepress/dist/assets/js/40.a764658c.js new file mode 100644 index 0000000..148fc46 --- /dev/null +++ b/.vuepress/dist/assets/js/40.a764658c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[40],{434:function(a,s,t){"use strict";t.r(s);var e=t(55),r=Object(e.a)({},(function(){var a=this,s=a.$createElement,t=a._self._c||s;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h1",{attrs:{id:"upgrade"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#upgrade"}},[a._v("#")]),a._v(" Upgrade")]),a._v(" "),t("p"),t("div",{staticClass:"table-of-contents"},[t("ul",[t("li",[t("a",{attrs:{href:"#upgrading-to-spark-paddle-2-0-from-v1-x"}},[a._v("Upgrading to Spark (Paddle) 2.0 From v1.x")]),t("ul",[t("li",[t("a",{attrs:{href:"#minimum-versions"}},[a._v("Minimum Versions")])])])])])]),t("p"),a._v(" "),t("h2",{attrs:{id:"upgrading-to-spark-paddle-2-0-from-v1-x"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#upgrading-to-spark-paddle-2-0-from-v1-x"}},[a._v("#")]),a._v(" Upgrading to Spark (Paddle) 2.0 From v1.x")]),a._v(" "),t("p",[a._v("Spark (Paddle) 2.0 is a maintenance release with no breaking changes. To upgrade, simply update your application's "),t("code",[a._v("composer.json")]),a._v(" file to depend on the latest release:")]),a._v(" "),t("div",{staticClass:"language-json extra-class"},[t("pre",{pre:!0,attrs:{class:"language-json"}},[t("code",[t("span",{pre:!0,attrs:{class:"token property"}},[a._v('"require"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[a._v('"php"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^8.0"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[a._v('"laravel/framework"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^9.0"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[a._v('"laravel/spark-paddle"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^2.0"')]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n")])])]),t("h3",{attrs:{id:"minimum-versions"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#minimum-versions"}},[a._v("#")]),a._v(" Minimum Versions")]),a._v(" "),t("p",[a._v("The following required dependency versions have been updated:")]),a._v(" "),t("ul",[t("li",[a._v("The minimum Laravel version is now v9.0")]),a._v(" "),t("li",[a._v("The minimum PHP version is now v8.0")])])])}),[],!1,null,null,null);s.default=r.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/41.f6cd3bbc.js b/.vuepress/dist/assets/js/41.803aa421.js similarity index 84% rename from .vuepress/dist/assets/js/41.f6cd3bbc.js rename to .vuepress/dist/assets/js/41.803aa421.js index 91b70a7..4ec0f0f 100644 --- a/.vuepress/dist/assets/js/41.f6cd3bbc.js +++ b/.vuepress/dist/assets/js/41.803aa421.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[41],{438:function(t,e,n){"use strict";n.r(e);var s=n(55),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("meta",{attrs:{"http-equiv":"refresh",content:"0;url=/docs/2.x/spark-paddle/configuration.html"}})])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[41],{435:function(t,e,n){"use strict";n.r(e);var s=n(55),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("meta",{attrs:{"http-equiv":"refresh",content:"0;url=/docs/2.x/spark-paddle/configuration.html"}})])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/22.db9640d4.js b/.vuepress/dist/assets/js/42.c55c2039.js similarity index 99% rename from .vuepress/dist/assets/js/22.db9640d4.js rename to .vuepress/dist/assets/js/42.c55c2039.js index 68121d9..b6df745 100644 --- a/.vuepress/dist/assets/js/22.db9640d4.js +++ b/.vuepress/dist/assets/js/42.c55c2039.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{416:function(t,a,s){"use strict";s.r(a);var e=s(55),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuration"}},[t._v("#")]),t._v(" Configuration")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#introduction"}},[t._v("Introduction")])]),s("li",[s("a",{attrs:{href:"#stripe-configuration"}},[t._v("Stripe Configuration")]),s("ul",[s("li",[s("a",{attrs:{href:"#environment-variables"}},[t._v("Environment Variables")])]),s("li",[s("a",{attrs:{href:"#stripe-webhooks"}},[t._v("Stripe Webhooks")])])])]),s("li",[s("a",{attrs:{href:"#configuring-billables"}},[t._v("Configuring Billables")]),s("ul",[s("li",[s("a",{attrs:{href:"#billable-slugs"}},[t._v("Billable Slugs")])]),s("li",[s("a",{attrs:{href:"#billable-resolution"}},[t._v("Billable Resolution")])]),s("li",[s("a",{attrs:{href:"#billable-authorization"}},[t._v("Billable Authorization")])])])]),s("li",[s("a",{attrs:{href:"#defining-subscription-plans"}},[t._v("Defining Subscription Plans")])]),s("li",[s("a",{attrs:{href:"#accessing-the-billing-portal"}},[t._v("Accessing The Billing Portal")])]),s("li",[s("a",{attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[t._v("Showing A Link To The Terms And Conditions")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"introduction"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),s("p",[t._v("In the following documentation, we will discuss how to configure a Laravel Spark installation when using the "),s("a",{attrs:{href:"https://stripe.com",target:"_blank",rel:"noopener noreferrer"}},[t._v("Stripe"),s("OutboundLink")],1),t._v(" payment provider. All of Spark's configuration options are housed in your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file.")]),t._v(" "),s("h2",{attrs:{id:"stripe-configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#stripe-configuration"}},[t._v("#")]),t._v(" Stripe Configuration")]),t._v(" "),s("p",[t._v("Of course, to use Stripe as a payment provider for your Laravel Spark application you must have an active "),s("a",{attrs:{href:"https://stripe.com",target:"_blank",rel:"noopener noreferrer"}},[t._v("Stripe account"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"environment-variables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#environment-variables"}},[t._v("#")]),t._v(" Environment Variables")]),t._v(" "),s("p",[t._v("Next, you should configure the application environment variables that will be needed by Spark in order to access your Stripe account. These variables should be placed in your application's "),s("code",[t._v(".env")]),t._v(" environment file.")]),t._v(" "),s("p",[t._v("Of course, you should adjust the variable's values to correspond to your own Stripe account's credentials. Your Stripe API credentials and public key are available in your Stripe account dashboard:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("CASHIER_CURRENCY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("USD\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("CASHIER_CURRENCY_LOCALE")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("en\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("STRIPE_KEY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("pk_test_example\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("STRIPE_SECRET")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("sk_test_example\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("STRIPE_WEBHOOK_SECRET")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("sk_test_example\n")])])]),s("div",{staticClass:"custom-block danger"},[s("p",{staticClass:"custom-block-title"},[t._v("Configuring Locales")]),t._v(" "),s("p",[t._v("In order to use locales other than "),s("code",[t._v("en")]),t._v(", ensure the "),s("code",[t._v("ext-intl")]),t._v(" PHP extension is installed and configured on your server.")])]),t._v(" "),s("h3",{attrs:{id:"stripe-webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#stripe-webhooks"}},[t._v("#")]),t._v(" Stripe Webhooks")]),t._v(" "),s("p",[t._v("In addition, your Spark powered application will need to receive webhooks from Stripe in order to keep your application's billing and subscription data in sync with Stripe's. Within your Stripe dashboard's webhook management panel, you should configure Stripe to send webhook alerts to your application's "),s("code",[t._v("/spark/webhook")]),t._v(" URI. You should enable webhook alerts for the following events:")]),t._v(" "),s("ul",[s("li",[t._v("customer.deleted")]),t._v(" "),s("li",[t._v("customer.subscription.created")]),t._v(" "),s("li",[t._v("customer.subscription.deleted")]),t._v(" "),s("li",[t._v("customer.subscription.updated")]),t._v(" "),s("li",[t._v("customer.updated")]),t._v(" "),s("li",[t._v("invoice.payment_action_required")]),t._v(" "),s("li",[t._v("invoice.payment_succeeded")])]),t._v(" "),s("h4",{attrs:{id:"webhooks-local-development"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks-local-development"}},[t._v("#")]),t._v(" Webhooks & Local Development")]),t._v(" "),s("p",[t._v("For Stripe to be able to send your application webhooks during local development, you will need to expose your application via a site sharing service such as "),s("a",{attrs:{href:"https://ngrok.io",target:"_blank",rel:"noopener noreferrer"}},[t._v("Ngrok"),s("OutboundLink")],1),t._v(" or "),s("a",{attrs:{href:"https://beyondco.de/docs/expose/introduction",target:"_blank",rel:"noopener noreferrer"}},[t._v("Expose"),s("OutboundLink")],1),t._v(". If you are developing your application locally using "),s("a",{attrs:{href:"http://laravel.com/docs/sail",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel Sail"),s("OutboundLink")],1),t._v(", you may use Sail's "),s("a",{attrs:{href:"https://laravel.com/docs/sail#sharing-your-site",target:"_blank",rel:"noopener noreferrer"}},[t._v("site sharing command"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"configuring-billables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuring-billables"}},[t._v("#")]),t._v(" Configuring Billables")]),t._v(" "),s("p",[t._v("Spark allows you to define the types of billable models that your application will be managing. Most commonly, applications bill individual users for monthly and yearly subscription plans. However, your application may choose to bill some other type of model, such as a team, organization, band, etc.")]),t._v(" "),s("p",[t._v("You may define your billable models within the "),s("code",[t._v("billables")]),t._v(" array of your application's "),s("code",[t._v("spark")]),t._v(" configuration file. By default, this array contains an entry for the "),s("code",[t._v("App\\Models\\User")]),t._v(" model.")]),t._v(" "),s("p",[t._v("Before continuing, you should ensure that the model class that corresponds to your billable model is using the "),s("code",[t._v("Spark\\Billable")]),t._v(" trait and that it casts the "),s("code",[t._v("trial_ends_at")]),t._v(" attribute to "),s("code",[t._v("datetime")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[t._v("")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'datetime'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]),s("h3",{attrs:{id:"billable-slugs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-slugs"}},[t._v("#")]),t._v(" Billable Slugs")]),t._v(" "),s("p",[t._v("As you may have noticed, each entry in the "),s("code",[t._v("billables")]),t._v(' configuration array is keyed by a "slug" that is a shortened form of the billable model class. This slug can be used when accessing the Spark customer billing portal, such as '),s("code",[t._v("https://example.com/billing/user")]),t._v(" or "),s("code",[t._v("https://example.com/billing/team")]),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"billable-resolution"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-resolution"}},[t._v("#")]),t._v(" Billable Resolution")]),t._v(" "),s("p",[t._v("When you installed Laravel Spark, an "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class was created for you. Within this service provider, you will find a callback that is used by Spark to resolve the billable model instance when accessing the Spark billing portal. By default, this callback simply returns the currently authenticated user, which is the desired behavior for most applications using Laravel Spark:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("However, if your application is not billing individual users, you may need to adjust this callback. For example, if your application offers team billing instead of user billing, you might customize the callback like so:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("currentTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("h3",{attrs:{id:"billable-authorization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-authorization"}},[t._v("#")]),t._v(" Billable Authorization")]),t._v(" "),s("p",[t._v("Next, let's examine the authorization callbacks that Spark will use to determine if the currently authenticated user of your application is authorized to view the billing portal for a particular billable model.")]),t._v(" "),s("p",[t._v("When you installed Laravel Spark, an "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class was created for you. Within this service provider, you will find the authorization callback definition used to determine if a given user is authorized to view the billing portal for the "),s("code",[t._v("App\\Models\\User")]),t._v(" billable class. Of course, if your application is not billing users, you should update the billable class and authorization callback logic to fit your application's needs. By default, Spark will simply verify that the currently authenticated user can only manage its own billing settings:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("User")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("id")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("If the authorization callback returns "),s("code",[t._v("true")]),t._v(", the currently authenticated user will be authorized to view the billing portal and manage the billing settings for the given "),s("code",[t._v("$billable")]),t._v(" model. If the callback returns "),s("code",[t._v("false")]),t._v(", the request to access the billing portal will be denied.")]),t._v(" "),s("p",[t._v("You are free to customize the "),s("code",[t._v("authorize")]),t._v(" callback based on your own application's needs. For example, if your application bills teams instead of individual users, you might update the callback like so:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ownsTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("h2",{attrs:{id:"defining-subscription-plans"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#defining-subscription-plans"}},[t._v("#")]),t._v(" Defining Subscription Plans")]),t._v(" "),s("p",[t._v("As we previously discussed, Spark allows you to define the types of billable models that your application will be managing. These billable models are defined within the "),s("code",[t._v("billables")]),t._v(" array of your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),s("p",[t._v("Each billable configuration within the "),s("code",[t._v("billables")]),t._v(" array contains a "),s("code",[t._v("plans")]),t._v(" array. Within this array you may configure each of the billing plans offered by your application to that particular billable type. "),s("strong",[t._v("The "),s("code",[t._v("monthly_id")]),t._v(" and "),s("code",[t._v("yearly_id")]),t._v(" identifiers should correspond to the price / plan identifiers configured within your Stripe account dashboard:")])]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'billables'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'user'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'model'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_days'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 1'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 2'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 3'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("p",[t._v("If your subscription plan only offers a monthly billing cycle, you may omit the "),s("code",[t._v("yearly_id")]),t._v(" identifier from your plan configuration. Likewise, if your plan only offers a yearly billing cycle, you may omit the "),s("code",[t._v("monthly_id")]),t._v(" identifier.")]),t._v(" "),s("p",[t._v("In addition, you are free to supply a short description of the plan and a list of features relevant to the plan. This information will be displayed in the Spark billing portal.")]),t._v(" "),s("h2",{attrs:{id:"accessing-the-billing-portal"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#accessing-the-billing-portal"}},[t._v("#")]),t._v(" Accessing The Billing Portal")]),t._v(" "),s("p",[t._v("Once you have configured your Spark installation, you may access your application's billing portal at the "),s("code",[t._v("/billing")]),t._v(" URI. So, if your application is being served on "),s("code",[t._v("localhost")]),t._v(", you may access your application's billing portal at "),s("code",[t._v("http://localhost/billing")]),t._v(".")]),t._v(" "),s("p",[t._v("Of course, you may link to the billing portal from your application's dashboard however you see fit:")]),t._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("href")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("/billing"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n Manage Subscription\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("h2",{attrs:{id:"showing-a-link-to-the-terms-and-conditions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[t._v("#")]),t._v(" Showing A Link To The Terms And Conditions")]),t._v(" "),s("p",[t._v("Many applications display billing terms and conditions during checkout. Spark allows you to easily do the same within your application's billing portal. To get started, add a "),s("code",[t._v("terms_url")]),t._v(" configuration value in your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'terms_url'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/terms'")]),t._v("\n")])])]),s("p",[t._v("Once added, Spark will display a link pointing to "),s("code",[t._v("/terms")]),t._v(" in the billing portal.")])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[42],{436:function(t,a,s){"use strict";s.r(a);var e=s(55),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuration"}},[t._v("#")]),t._v(" Configuration")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#introduction"}},[t._v("Introduction")])]),s("li",[s("a",{attrs:{href:"#stripe-configuration"}},[t._v("Stripe Configuration")]),s("ul",[s("li",[s("a",{attrs:{href:"#environment-variables"}},[t._v("Environment Variables")])]),s("li",[s("a",{attrs:{href:"#stripe-webhooks"}},[t._v("Stripe Webhooks")])])])]),s("li",[s("a",{attrs:{href:"#configuring-billables"}},[t._v("Configuring Billables")]),s("ul",[s("li",[s("a",{attrs:{href:"#billable-slugs"}},[t._v("Billable Slugs")])]),s("li",[s("a",{attrs:{href:"#billable-resolution"}},[t._v("Billable Resolution")])]),s("li",[s("a",{attrs:{href:"#billable-authorization"}},[t._v("Billable Authorization")])])])]),s("li",[s("a",{attrs:{href:"#defining-subscription-plans"}},[t._v("Defining Subscription Plans")])]),s("li",[s("a",{attrs:{href:"#accessing-the-billing-portal"}},[t._v("Accessing The Billing Portal")])]),s("li",[s("a",{attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[t._v("Showing A Link To The Terms And Conditions")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"introduction"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),s("p",[t._v("In the following documentation, we will discuss how to configure a Laravel Spark installation when using the "),s("a",{attrs:{href:"https://stripe.com",target:"_blank",rel:"noopener noreferrer"}},[t._v("Stripe"),s("OutboundLink")],1),t._v(" payment provider. All of Spark's configuration options are housed in your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file.")]),t._v(" "),s("h2",{attrs:{id:"stripe-configuration"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#stripe-configuration"}},[t._v("#")]),t._v(" Stripe Configuration")]),t._v(" "),s("p",[t._v("Of course, to use Stripe as a payment provider for your Laravel Spark application you must have an active "),s("a",{attrs:{href:"https://stripe.com",target:"_blank",rel:"noopener noreferrer"}},[t._v("Stripe account"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"environment-variables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#environment-variables"}},[t._v("#")]),t._v(" Environment Variables")]),t._v(" "),s("p",[t._v("Next, you should configure the application environment variables that will be needed by Spark in order to access your Stripe account. These variables should be placed in your application's "),s("code",[t._v(".env")]),t._v(" environment file.")]),t._v(" "),s("p",[t._v("Of course, you should adjust the variable's values to correspond to your own Stripe account's credentials. Your Stripe API credentials and public key are available in your Stripe account dashboard:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("CASHIER_CURRENCY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("USD\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("CASHIER_CURRENCY_LOCALE")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("en\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("STRIPE_KEY")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("pk_test_example\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("STRIPE_SECRET")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("sk_test_example\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("STRIPE_WEBHOOK_SECRET")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("sk_test_example\n")])])]),s("div",{staticClass:"custom-block danger"},[s("p",{staticClass:"custom-block-title"},[t._v("Configuring Locales")]),t._v(" "),s("p",[t._v("In order to use locales other than "),s("code",[t._v("en")]),t._v(", ensure the "),s("code",[t._v("ext-intl")]),t._v(" PHP extension is installed and configured on your server.")])]),t._v(" "),s("h3",{attrs:{id:"stripe-webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#stripe-webhooks"}},[t._v("#")]),t._v(" Stripe Webhooks")]),t._v(" "),s("p",[t._v("In addition, your Spark powered application will need to receive webhooks from Stripe in order to keep your application's billing and subscription data in sync with Stripe's. Within your Stripe dashboard's webhook management panel, you should configure Stripe to send webhook alerts to your application's "),s("code",[t._v("/spark/webhook")]),t._v(" URI. You should enable webhook alerts for the following events:")]),t._v(" "),s("ul",[s("li",[t._v("customer.deleted")]),t._v(" "),s("li",[t._v("customer.subscription.created")]),t._v(" "),s("li",[t._v("customer.subscription.deleted")]),t._v(" "),s("li",[t._v("customer.subscription.updated")]),t._v(" "),s("li",[t._v("customer.updated")]),t._v(" "),s("li",[t._v("invoice.payment_action_required")]),t._v(" "),s("li",[t._v("invoice.payment_succeeded")])]),t._v(" "),s("h4",{attrs:{id:"webhooks-local-development"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks-local-development"}},[t._v("#")]),t._v(" Webhooks & Local Development")]),t._v(" "),s("p",[t._v("For Stripe to be able to send your application webhooks during local development, you will need to expose your application via a site sharing service such as "),s("a",{attrs:{href:"https://ngrok.io",target:"_blank",rel:"noopener noreferrer"}},[t._v("Ngrok"),s("OutboundLink")],1),t._v(" or "),s("a",{attrs:{href:"https://beyondco.de/docs/expose/introduction",target:"_blank",rel:"noopener noreferrer"}},[t._v("Expose"),s("OutboundLink")],1),t._v(". If you are developing your application locally using "),s("a",{attrs:{href:"http://laravel.com/docs/sail",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel Sail"),s("OutboundLink")],1),t._v(", you may use Sail's "),s("a",{attrs:{href:"https://laravel.com/docs/sail#sharing-your-site",target:"_blank",rel:"noopener noreferrer"}},[t._v("site sharing command"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"configuring-billables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#configuring-billables"}},[t._v("#")]),t._v(" Configuring Billables")]),t._v(" "),s("p",[t._v("Spark allows you to define the types of billable models that your application will be managing. Most commonly, applications bill individual users for monthly and yearly subscription plans. However, your application may choose to bill some other type of model, such as a team, organization, band, etc.")]),t._v(" "),s("p",[t._v("You may define your billable models within the "),s("code",[t._v("billables")]),t._v(" array of your application's "),s("code",[t._v("spark")]),t._v(" configuration file. By default, this array contains an entry for the "),s("code",[t._v("App\\Models\\User")]),t._v(" model.")]),t._v(" "),s("p",[t._v("Before continuing, you should ensure that the model class that corresponds to your billable model is using the "),s("code",[t._v("Spark\\Billable")]),t._v(" trait and that it casts the "),s("code",[t._v("trial_ends_at")]),t._v(" attribute to "),s("code",[t._v("datetime")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[t._v("")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'datetime'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]),s("h3",{attrs:{id:"billable-slugs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-slugs"}},[t._v("#")]),t._v(" Billable Slugs")]),t._v(" "),s("p",[t._v("As you may have noticed, each entry in the "),s("code",[t._v("billables")]),t._v(' configuration array is keyed by a "slug" that is a shortened form of the billable model class. This slug can be used when accessing the Spark customer billing portal, such as '),s("code",[t._v("https://example.com/billing/user")]),t._v(" or "),s("code",[t._v("https://example.com/billing/team")]),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"billable-resolution"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-resolution"}},[t._v("#")]),t._v(" Billable Resolution")]),t._v(" "),s("p",[t._v("When you installed Laravel Spark, an "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class was created for you. Within this service provider, you will find a callback that is used by Spark to resolve the billable model instance when accessing the Spark billing portal. By default, this callback simply returns the currently authenticated user, which is the desired behavior for most applications using Laravel Spark:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("However, if your application is not billing individual users, you may need to adjust this callback. For example, if your application offers team billing instead of user billing, you might customize the callback like so:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("currentTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("h3",{attrs:{id:"billable-authorization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#billable-authorization"}},[t._v("#")]),t._v(" Billable Authorization")]),t._v(" "),s("p",[t._v("Next, let's examine the authorization callbacks that Spark will use to determine if the currently authenticated user of your application is authorized to view the billing portal for a particular billable model.")]),t._v(" "),s("p",[t._v("When you installed Laravel Spark, an "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class was created for you. Within this service provider, you will find the authorization callback definition used to determine if a given user is authorized to view the billing portal for the "),s("code",[t._v("App\\Models\\User")]),t._v(" billable class. Of course, if your application is not billing users, you should update the billable class and authorization callback logic to fit your application's needs. By default, Spark will simply verify that the currently authenticated user can only manage its own billing settings:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("User")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("id")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("If the authorization callback returns "),s("code",[t._v("true")]),t._v(", the currently authenticated user will be authorized to view the billing portal and manage the billing settings for the given "),s("code",[t._v("$billable")]),t._v(" model. If the callback returns "),s("code",[t._v("false")]),t._v(", the request to access the billing portal will be denied.")]),t._v(" "),s("p",[t._v("You are free to customize the "),s("code",[t._v("authorize")]),t._v(" callback based on your own application's needs. For example, if your application bills teams instead of individual users, you might update the callback like so:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ownsTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("h2",{attrs:{id:"defining-subscription-plans"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#defining-subscription-plans"}},[t._v("#")]),t._v(" Defining Subscription Plans")]),t._v(" "),s("p",[t._v("As we previously discussed, Spark allows you to define the types of billable models that your application will be managing. These billable models are defined within the "),s("code",[t._v("billables")]),t._v(" array of your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),s("p",[t._v("Each billable configuration within the "),s("code",[t._v("billables")]),t._v(" array contains a "),s("code",[t._v("plans")]),t._v(" array. Within this array you may configure each of the billing plans offered by your application to that particular billable type. "),s("strong",[t._v("The "),s("code",[t._v("monthly_id")]),t._v(" and "),s("code",[t._v("yearly_id")]),t._v(" identifiers should correspond to the price / plan identifiers configured within your Stripe account dashboard:")])]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'billables'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'user'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'model'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_days'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 1'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 2'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 3'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("p",[t._v("If your subscription plan only offers a monthly billing cycle, you may omit the "),s("code",[t._v("yearly_id")]),t._v(" identifier from your plan configuration. Likewise, if your plan only offers a yearly billing cycle, you may omit the "),s("code",[t._v("monthly_id")]),t._v(" identifier.")]),t._v(" "),s("p",[t._v("In addition, you are free to supply a short description of the plan and a list of features relevant to the plan. This information will be displayed in the Spark billing portal.")]),t._v(" "),s("h2",{attrs:{id:"accessing-the-billing-portal"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#accessing-the-billing-portal"}},[t._v("#")]),t._v(" Accessing The Billing Portal")]),t._v(" "),s("p",[t._v("Once you have configured your Spark installation, you may access your application's billing portal at the "),s("code",[t._v("/billing")]),t._v(" URI. So, if your application is being served on "),s("code",[t._v("localhost")]),t._v(", you may access your application's billing portal at "),s("code",[t._v("http://localhost/billing")]),t._v(".")]),t._v(" "),s("p",[t._v("Of course, you may link to the billing portal from your application's dashboard however you see fit:")]),t._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("href")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("/billing"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n Manage Subscription\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("h2",{attrs:{id:"showing-a-link-to-the-terms-and-conditions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#showing-a-link-to-the-terms-and-conditions"}},[t._v("#")]),t._v(" Showing A Link To The Terms And Conditions")]),t._v(" "),s("p",[t._v("Many applications display billing terms and conditions during checkout. Spark allows you to easily do the same within your application's billing portal. To get started, add a "),s("code",[t._v("terms_url")]),t._v(" configuration value in your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'terms_url'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/terms'")]),t._v("\n")])])]),s("p",[t._v("Once added, Spark will display a link pointing to "),s("code",[t._v("/terms")]),t._v(" in the billing portal.")])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/23.5c58e10a.js b/.vuepress/dist/assets/js/43.63f50d56.js similarity index 99% rename from .vuepress/dist/assets/js/23.5c58e10a.js rename to .vuepress/dist/assets/js/43.63f50d56.js index 9578946..02ab64e 100644 --- a/.vuepress/dist/assets/js/23.5c58e10a.js +++ b/.vuepress/dist/assets/js/43.63f50d56.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{417:function(t,a,s){"use strict";s.r(a);var e=s(55),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"cookbook"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#cookbook"}},[t._v("#")]),t._v(" Cookbook")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#team-billing"}},[t._v("Team Billing")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"team-billing"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#team-billing"}},[t._v("#")]),t._v(" Team Billing")]),t._v(" "),s("p",[t._v('Spark ships with "user" based billing by default. If your applications bills teams or a different model instead, you will need to adjust your Spark installation accordingly. We\'ll walk through these adjustments in the following documentation using a team billing implementation as an example.')]),t._v(" "),s("p",[t._v("To make the "),s("code",[t._v("App\\Models\\Team")]),t._v(" model our billable model, we first need to adjust Spark's default migrations. So, let's configure Spark to ignore its own default migrations and export the migrations to our application so that we can adjust them:")]),t._v(" "),s("h4",{attrs:{id:"customizing-the-migrations"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#customizing-the-migrations"}},[t._v("#")]),t._v(" Customizing The Migrations")]),t._v(" "),s("p",[t._v("To instruct Spark to ignore its migrations, call the "),s("code",[t._v("Spark::ignoreMigrations()")]),t._v(" method in the "),s("code",[t._v("register")]),t._v(" method of your application's "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ignoreMigrations")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("Next, execute the following Artisan command to publish the migrations:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-migrations\n")])])]),s("p",[t._v("Now that the migrations are published in the "),s("code",[t._v("/database/migrations")]),t._v(" directory, we need to change the name of the "),s("code",[t._v("2019_05_03_000001_add_spark_columns_to_users_table.php")]),t._v(" file to "),s("code",[t._v("2020_05_03_000001_add_spark_columns_to_teams_table.php")]),t._v('. Adjusting the "year" of the migration will ensure the migration is run after the '),s("code",[t._v("teams")]),t._v(" table is created in the database.")]),t._v(" "),s("p",[t._v("After renaming the migration, you may update its contents such that it updates the table definition of the "),s("code",[t._v("teams")]),t._v(" table instead of the "),s("code",[t._v("users")]),t._v(" table. Also, update the first column so that it is added after a field on the "),s("code",[t._v("teams")]),t._v(" table instead of "),s("code",[t._v("remember_token")]),t._v(".")]),t._v(" "),s("p",[t._v("Next, update the "),s("code",[t._v("subscriptions")]),t._v(" table migration to contain "),s("code",[t._v("team_id")]),t._v("instead of "),s("code",[t._v("user_id")]),t._v(". You should also ensure that you update the column in the migration's index as well.")]),t._v(" "),s("p",[t._v("Finally, you also need to update the migration of the "),s("code",[t._v("receipts")]),t._v(" table to use the "),s("code",[t._v("team_id")]),t._v(" column instead of "),s("code",[t._v("user_id")]),t._v(".")]),t._v(" "),s("h4",{attrs:{id:"updating-the-service-provider"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-service-provider"}},[t._v("#")]),t._v(" Updating The Service Provider")]),t._v(" "),s("p",[t._v("Now that the migrations have been updated, we should update the "),s("code",[t._v("SparkServiceProvider")]),t._v(" to reference the "),s("code",[t._v("Team")]),t._v(" model instead of the "),s("code",[t._v("User")]),t._v(" model:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("SparkServiceProvider")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServiceProvider")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Bootstrap any application services.\n *\n * @return void\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("boot")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Resolve the current team...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("currentTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Verify that the current user owns the team...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("id")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("user_id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkPlanEligibility")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Plan")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h4",{attrs:{id:"environment-variables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#environment-variables"}},[t._v("#")]),t._v(" Environment Variables")]),t._v(" "),s("p",[t._v("Next, update the "),s("code",[t._v("CASHIER_MODEL")]),t._v(" environment variable to use the "),s("code",[t._v("Team")]),t._v(" model instead of the "),s("code",[t._v("User")]),t._v(" model:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("CASHIER_MODEL")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team\n")])])]),s("h4",{attrs:{id:"updating-the-model"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-model"}},[t._v("#")]),t._v(" Updating The Model")]),t._v(" "),s("p",[t._v("Now we can update the "),s("code",[t._v("Team")]),t._v(" model to use the "),s("code",[t._v("Spark\\Billable")]),t._v(" trait and implement a "),s("code",[t._v("stripeEmail")]),t._v(" method that returns the team owner's email address to be displayed in the Stripe dashboard as the customer identifier:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JetstreamTeam")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("stripeEmail")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$this")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("owner")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("email")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h4",{attrs:{id:"spark-configuration-file"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#spark-configuration-file"}},[t._v("#")]),t._v(" Spark Configuration File")]),t._v(" "),s("p",[t._v("Finally, update your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file so that it defines a "),s("code",[t._v("team")]),t._v(" billable model:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'billables'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'team'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'model'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[43],{437:function(t,a,s){"use strict";s.r(a);var e=s(55),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"cookbook"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#cookbook"}},[t._v("#")]),t._v(" Cookbook")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#team-billing"}},[t._v("Team Billing")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"team-billing"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#team-billing"}},[t._v("#")]),t._v(" Team Billing")]),t._v(" "),s("p",[t._v('Spark ships with "user" based billing by default. If your applications bills teams or a different model instead, you will need to adjust your Spark installation accordingly. We\'ll walk through these adjustments in the following documentation using a team billing implementation as an example.')]),t._v(" "),s("p",[t._v("To make the "),s("code",[t._v("App\\Models\\Team")]),t._v(" model our billable model, we first need to adjust Spark's default migrations. So, let's configure Spark to ignore its own default migrations and export the migrations to our application so that we can adjust them:")]),t._v(" "),s("h4",{attrs:{id:"customizing-the-migrations"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#customizing-the-migrations"}},[t._v("#")]),t._v(" Customizing The Migrations")]),t._v(" "),s("p",[t._v("To instruct Spark to ignore its migrations, call the "),s("code",[t._v("Spark::ignoreMigrations()")]),t._v(" method in the "),s("code",[t._v("register")]),t._v(" method of your application's "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ignoreMigrations")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("Next, execute the following Artisan command to publish the migrations:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-migrations\n")])])]),s("p",[t._v("Now that the migrations are published in the "),s("code",[t._v("/database/migrations")]),t._v(" directory, we need to change the name of the "),s("code",[t._v("2019_05_03_000001_add_spark_columns_to_users_table.php")]),t._v(" file to "),s("code",[t._v("2020_05_03_000001_add_spark_columns_to_teams_table.php")]),t._v('. Adjusting the "year" of the migration will ensure the migration is run after the '),s("code",[t._v("teams")]),t._v(" table is created in the database.")]),t._v(" "),s("p",[t._v("After renaming the migration, you may update its contents such that it updates the table definition of the "),s("code",[t._v("teams")]),t._v(" table instead of the "),s("code",[t._v("users")]),t._v(" table. Also, update the first column so that it is added after a field on the "),s("code",[t._v("teams")]),t._v(" table instead of "),s("code",[t._v("remember_token")]),t._v(".")]),t._v(" "),s("p",[t._v("Next, update the "),s("code",[t._v("subscriptions")]),t._v(" table migration to contain "),s("code",[t._v("team_id")]),t._v("instead of "),s("code",[t._v("user_id")]),t._v(". You should also ensure that you update the column in the migration's index as well.")]),t._v(" "),s("p",[t._v("Finally, you also need to update the migration of the "),s("code",[t._v("receipts")]),t._v(" table to use the "),s("code",[t._v("team_id")]),t._v(" column instead of "),s("code",[t._v("user_id")]),t._v(".")]),t._v(" "),s("h4",{attrs:{id:"updating-the-service-provider"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-service-provider"}},[t._v("#")]),t._v(" Updating The Service Provider")]),t._v(" "),s("p",[t._v("Now that the migrations have been updated, we should update the "),s("code",[t._v("SparkServiceProvider")]),t._v(" to reference the "),s("code",[t._v("Team")]),t._v(" model instead of the "),s("code",[t._v("User")]),t._v(" model:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("SparkServiceProvider")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServiceProvider")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Bootstrap any application services.\n *\n * @return void\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("boot")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Resolve the current team...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("resolve")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("currentTeam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Verify that the current user owns the team...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("authorize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Request")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$request")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("id")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("user_id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkPlanEligibility")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Plan")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h4",{attrs:{id:"environment-variables"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#environment-variables"}},[t._v("#")]),t._v(" Environment Variables")]),t._v(" "),s("p",[t._v("Next, update the "),s("code",[t._v("CASHIER_MODEL")]),t._v(" environment variable to use the "),s("code",[t._v("Team")]),t._v(" model instead of the "),s("code",[t._v("User")]),t._v(" model:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("CASHIER_MODEL")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team\n")])])]),s("h4",{attrs:{id:"updating-the-model"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-model"}},[t._v("#")]),t._v(" Updating The Model")]),t._v(" "),s("p",[t._v("Now we can update the "),s("code",[t._v("Team")]),t._v(" model to use the "),s("code",[t._v("Spark\\Billable")]),t._v(" trait and implement a "),s("code",[t._v("stripeEmail")]),t._v(" method that returns the team owner's email address to be displayed in the Stripe dashboard as the customer identifier:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("Team")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("JetstreamTeam")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Billable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("stripeEmail")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$this")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("owner")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("email")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h4",{attrs:{id:"spark-configuration-file"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#spark-configuration-file"}},[t._v("#")]),t._v(" Spark Configuration File")]),t._v(" "),s("p",[t._v("Finally, update your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file so that it defines a "),s("code",[t._v("team")]),t._v(" billable model:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Team")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'billables'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'team'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'model'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Team")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/44.f9b6e351.js b/.vuepress/dist/assets/js/44.ee3a873b.js similarity index 99% rename from .vuepress/dist/assets/js/44.f9b6e351.js rename to .vuepress/dist/assets/js/44.ee3a873b.js index 54a14b0..1cccf27 100644 --- a/.vuepress/dist/assets/js/44.f9b6e351.js +++ b/.vuepress/dist/assets/js/44.ee3a873b.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[44],{440:function(t,a,s){"use strict";s.r(a);var n=s(55),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"customization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#customization"}},[t._v("#")]),t._v(" Customization")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#branding"}},[t._v("Branding")]),s("ul",[s("li",[s("a",{attrs:{href:"#brand-logo"}},[t._v("Brand Logo")])]),s("li",[s("a",{attrs:{href:"#brand-color"}},[t._v("Brand Color")])]),s("li",[s("a",{attrs:{href:"#font"}},[t._v("Font")])])])]),s("li",[s("a",{attrs:{href:"#localization"}},[t._v("Localization")])]),s("li",[s("a",{attrs:{href:"#migrations"}},[t._v("Migrations")])]),s("li",[s("a",{attrs:{href:"#webhooks"}},[t._v("Webhooks")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"branding"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#branding"}},[t._v("#")]),t._v(" Branding")]),t._v(" "),s("p",[t._v("Although Spark's billing portal is intended to be an isolated part of your application that is entirely managed by Spark, you can make some small customizations to the branding logo and color used by Spark.")]),t._v(" "),s("h3",{attrs:{id:"brand-logo"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#brand-logo"}},[t._v("#")]),t._v(" Brand Logo")]),t._v(" "),s("p",[t._v("To customize the logo used at the top left of the Spark billing portal, you may specify a configuration value for the "),s("code",[t._v("brand.logo")]),t._v(" configuration item within your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file. This configuration value should contain an absolute path to the SVG file of the logo you would like to use:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'brand'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'logo'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("realpath")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("__DIR__")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/../public/img/logo.svg'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("SVG Sizing")]),t._v(" "),s("p",[t._v("You may need to adjust the size and width of your SVG logo by modifying its width in the SVG file itself.")])]),t._v(" "),s("h3",{attrs:{id:"brand-color"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#brand-color"}},[t._v("#")]),t._v(" Brand Color")]),t._v(" "),s("p",[t._v("To customize the color used as the background color of the button elements within the Spark billing portal, you may specify a value for the "),s("code",[t._v("brand.color")]),t._v(" configuration item within your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file. This configuration value should be a valid hex code or correspond to a background color offered by the "),s("a",{attrs:{href:"https://tailwindcss.com/docs/customizing-colors",target:"_blank",rel:"noopener noreferrer"}},[t._v("Tailwind CSS framework"),s("OutboundLink")],1),t._v(":")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'brand'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'bg-indigo-600'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Or...")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'#c5b358'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("h3",{attrs:{id:"font"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#font"}},[t._v("#")]),t._v(" Font")]),t._v(" "),s("p",[t._v("To customize the font used by the Spark billing portal, you should export Spark's views using the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-views\n")])])]),s("p",[t._v("Next, within the "),s("code",[t._v("resources/views/vendor/spark/app.blade.php")]),t._v(" template, you may define your own "),s("code",[t._v("font-sans")]),t._v(" CSS class at the bottom of the templates "),s("code",[t._v("head")]),t._v(" section:")]),t._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("head")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("\x3c!-- ...... --\x3e")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("style")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token style"}},[s("span",{pre:!0,attrs:{class:"token language-css"}},[t._v("\n "),s("span",{pre:!0,attrs:{class:"token selector"}},[t._v(".font-sans")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("font-family")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Your Custom Font'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n ")])]),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("h2",{attrs:{id:"localization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#localization"}},[t._v("#")]),t._v(" Localization")]),t._v(" "),s("p",[t._v("You may localize / translate all of the text within the Spark billing portal. To publish the Spark localization file, you may use the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-lang\n")])])]),s("p",[t._v("This command will publish a "),s("code",[t._v("resources/lang/spark/en.json")]),t._v(" file containing translation keys and values for the English language. You may copy this file and translate it to the language of your choice. For more information on how to use Laravel's translation features, please consult the "),s("a",{attrs:{href:"https://laravel.com/docs/localization#using-translation-strings-as-keys",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel localization documentation"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"migrations"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#migrations"}},[t._v("#")]),t._v(" Migrations")]),t._v(" "),s("p",[t._v("Most commonly, applications bill individual users for monthly and yearly subscription plans. However, your application may choose to bill some other type of model, such as a team, organization, band, etc.")]),t._v(" "),s("p",[t._v("In that case, you should add "),s("code",[t._v("Spark::ignoreMigrations()")]),t._v(" in the register method of your application's "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("SparkServiceProvider")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServiceProvider")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Register any application services.\n *\n * @return void\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ignoreMigrations")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("Next, you should publish the Spark migrations by running the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"spark-migrations"')]),t._v("\n")])])]),s("p",[t._v("Finally, you should inspect the published migrations and update the "),s("code",[t._v("2019_05_03_000001_add_spark_columns_to_users_table.php")]),t._v(" file to add the columns needed by Spark to the table that will be used by your application's billable model.")]),t._v(" "),s("h2",{attrs:{id:"webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks"}},[t._v("#")]),t._v(" Webhooks")]),t._v(" "),s("p",[t._v("Spark and Cashier automatically handle subscription cancellations for failed charges and other common Stripe webhook events. However, if you have additional webhook events you would like to handle, you may do so by extending the Spark webhook controller.")]),t._v(" "),s("p",[t._v("Your controller's method names should correspond to Cashier's controller conventions. Specifically, methods should be prefixed with "),s("code",[t._v("handle")]),t._v(' and the "camel case" name of the webhook you wish to handle. For example, if you wish to handle the '),s("code",[t._v("invoice.payment_succeeded")]),t._v(" webhook, you should add a "),s("code",[t._v("handleInvoicePaymentSucceeded")]),t._v(" method to the controller:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[t._v("")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'logo'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("realpath")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("__DIR__")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/../public/img/logo.svg'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("SVG Sizing")]),t._v(" "),s("p",[t._v("You may need to adjust the size and width of your SVG logo by modifying its width in the SVG file itself.")])]),t._v(" "),s("h3",{attrs:{id:"brand-color"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#brand-color"}},[t._v("#")]),t._v(" Brand Color")]),t._v(" "),s("p",[t._v("To customize the color used as the background color of the button elements within the Spark billing portal, you may specify a value for the "),s("code",[t._v("brand.color")]),t._v(" configuration item within your application's "),s("code",[t._v("config/spark.php")]),t._v(" configuration file. This configuration value should be a valid hex code or correspond to a background color offered by the "),s("a",{attrs:{href:"https://tailwindcss.com/docs/customizing-colors",target:"_blank",rel:"noopener noreferrer"}},[t._v("Tailwind CSS framework"),s("OutboundLink")],1),t._v(":")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'brand'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'bg-indigo-600'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Or...")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'color'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'#c5b358'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("h3",{attrs:{id:"font"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#font"}},[t._v("#")]),t._v(" Font")]),t._v(" "),s("p",[t._v("To customize the font used by the Spark billing portal, you should export Spark's views using the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-views\n")])])]),s("p",[t._v("Next, within the "),s("code",[t._v("resources/views/vendor/spark/app.blade.php")]),t._v(" template, you may define your own "),s("code",[t._v("font-sans")]),t._v(" CSS class at the bottom of the templates "),s("code",[t._v("head")]),t._v(" section:")]),t._v(" "),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("head")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("\x3c!-- ...... --\x3e")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("style")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token style"}},[s("span",{pre:!0,attrs:{class:"token language-css"}},[t._v("\n "),s("span",{pre:!0,attrs:{class:"token selector"}},[t._v(".font-sans")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token property"}},[t._v("font-family")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Your Custom Font'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n ")])]),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("h2",{attrs:{id:"localization"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#localization"}},[t._v("#")]),t._v(" Localization")]),t._v(" "),s("p",[t._v("You may localize / translate all of the text within the Spark billing portal. To publish the Spark localization file, you may use the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("spark-lang\n")])])]),s("p",[t._v("This command will publish a "),s("code",[t._v("resources/lang/spark/en.json")]),t._v(" file containing translation keys and values for the English language. You may copy this file and translate it to the language of your choice. For more information on how to use Laravel's translation features, please consult the "),s("a",{attrs:{href:"https://laravel.com/docs/localization#using-translation-strings-as-keys",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel localization documentation"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"migrations"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#migrations"}},[t._v("#")]),t._v(" Migrations")]),t._v(" "),s("p",[t._v("Most commonly, applications bill individual users for monthly and yearly subscription plans. However, your application may choose to bill some other type of model, such as a team, organization, band, etc.")]),t._v(" "),s("p",[t._v("In that case, you should add "),s("code",[t._v("Spark::ignoreMigrations()")]),t._v(" in the register method of your application's "),s("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name-definition class-name"}},[t._v("SparkServiceProvider")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServiceProvider")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Register any application services.\n *\n * @return void\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ignoreMigrations")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("Next, you should publish the Spark migrations by running the "),s("code",[t._v("vendor:publish")]),t._v(" Artisan command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan vendor:publish --tag"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"spark-migrations"')]),t._v("\n")])])]),s("p",[t._v("Finally, you should inspect the published migrations and update the "),s("code",[t._v("2019_05_03_000001_add_spark_columns_to_users_table.php")]),t._v(" file to add the columns needed by Spark to the table that will be used by your application's billable model.")]),t._v(" "),s("h2",{attrs:{id:"webhooks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#webhooks"}},[t._v("#")]),t._v(" Webhooks")]),t._v(" "),s("p",[t._v("Spark and Cashier automatically handle subscription cancellations for failed charges and other common Stripe webhook events. However, if you have additional webhook events you would like to handle, you may do so by extending the Spark webhook controller.")]),t._v(" "),s("p",[t._v("Your controller's method names should correspond to Cashier's controller conventions. Specifically, methods should be prefixed with "),s("code",[t._v("handle")]),t._v(' and the "camel case" name of the webhook you wish to handle. For example, if you wish to handle the '),s("code",[t._v("invoice.payment_succeeded")]),t._v(" webhook, you should add a "),s("code",[t._v("handleInvoicePaymentSucceeded")]),t._v(" method to the controller:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token php language-php"}},[s("span",{pre:!0,attrs:{class:"token delimiter important"}},[t._v("")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("VerifyBillableIsSubscribed")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Once the middleware has been registered, you may attach it to any of your application's route definitions:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Route")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("post")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/projects'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ProjectController")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'store'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("middleware")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'auth'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("If the user has an active subscription, the request will continue to execute normally. However, if the user does not have an active subscription, they will be redirected to your application's Spark billing portal. If the request is an XHR request, a response with a 402 HTTP status code will be returned to the client.")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("Manually Inspecting Subscription States")]),t._v(" "),a("p",[t._v("Of course, you may always manually inspect a billable model's subscription status using the "),a("a",{attrs:{href:"https://laravel.com/docs/billing#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),a("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan.")])])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[46],{440:function(t,s,a){"use strict";a.r(s);var e=a(55),n=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"middleware"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#middleware"}},[t._v("#")]),t._v(" Middleware")]),t._v(" "),a("p"),a("div",{staticClass:"table-of-contents"},[a("ul")]),a("p"),t._v(" "),a("p",[t._v("When building a subscription based application, you will commonly need to restrict access to certain routes to users that have an active subscription. For example, you may not want to let a user create a project if they are not subscribed to a billing plan. For that reason, Spark provides a convenient subscription verification "),a("a",{attrs:{href:"https://laravel.com/docs/middleware",target:"_blank",rel:"noopener noreferrer"}},[t._v("middleware"),a("OutboundLink")],1),t._v(" that you may register with your application.")]),t._v(" "),a("p",[t._v("To get started, register Spark's subscription verification middleware in your HTTP kernel's "),a("code",[t._v("$routeMiddleware")]),t._v(" array. Your application's HTTP kernel is typically located at "),a("code",[t._v("app/Http/Kernel.php")]),t._v(":")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Http"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Middleware"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("VerifyBillableIsSubscribed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("protected")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$routeMiddleware")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("VerifyBillableIsSubscribed")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Once the middleware has been registered, you may attach it to any of your application's route definitions:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Route")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("post")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'/projects'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ProjectController")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'store'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("middleware")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'auth'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscribed'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("If the user has an active subscription, the request will continue to execute normally. However, if the user does not have an active subscription, they will be redirected to your application's Spark billing portal. If the request is an XHR request, a response with a 402 HTTP status code will be returned to the client.")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("Manually Inspecting Subscription States")]),t._v(" "),a("p",[t._v("Of course, you may always manually inspect a billable model's subscription status using the "),a("a",{attrs:{href:"https://laravel.com/docs/billing#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),a("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan.")])])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/48.38168e03.js b/.vuepress/dist/assets/js/48.5e3bfa48.js similarity index 99% rename from .vuepress/dist/assets/js/48.38168e03.js rename to .vuepress/dist/assets/js/48.5e3bfa48.js index b6d20f2..4469937 100644 --- a/.vuepress/dist/assets/js/48.38168e03.js +++ b/.vuepress/dist/assets/js/48.5e3bfa48.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[48],{445:function(t,s,a){"use strict";a.r(s);var n=a(55),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"testing"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#testing"}},[t._v("#")]),t._v(" Testing")]),t._v(" "),a("p"),a("div",{staticClass:"table-of-contents"},[a("ul",[a("li",[a("a",{attrs:{href:"#factories"}},[t._v("Factories")])])])]),a("p"),t._v(" "),a("h2",{attrs:{id:"factories"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#factories"}},[t._v("#")]),t._v(" Factories")]),t._v(" "),a("p",[t._v('While developing your application, you will likely want to "stub" a subscription record in your application\'s database so that calls to the '),a("code",[t._v("$billable->subscribed()")]),t._v(" method return "),a("code",[t._v("true")]),t._v(".")]),t._v(" "),a("p",[t._v('To accomplish this, you may add a "state" method to your billable model\'s '),a("a",{attrs:{href:"https://laravel.com/docs/database-testing#defining-model-factories",target:"_blank",rel:"noopener noreferrer"}},[t._v("factory class"),a("OutboundLink")],1),t._v(". Typically, this will be your application's "),a("code",[t._v("UserFactory")]),t._v(" class. Below you will find an example state method implementation; however, you are free to adjust this to your application's own needs:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Indicate that the user should have a subscription plan.\n *\n * @param string $planId\n * @return \\Illuminate\\Database\\Eloquent\\Factories\\Factory\n */")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$this")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("afterCreating")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$subscription")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscriptions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'default'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_id'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Str")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("random")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_status'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'active'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_price'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'quantity'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$subscription")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("items")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_id'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Str")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("random")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_product'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Str")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("random")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_price'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'quantity'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Once you have define the state method, you may use it when creating models via your factory:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("factory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// true")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[48],{443:function(t,s,a){"use strict";a.r(s);var n=a(55),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"testing"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#testing"}},[t._v("#")]),t._v(" Testing")]),t._v(" "),a("p"),a("div",{staticClass:"table-of-contents"},[a("ul",[a("li",[a("a",{attrs:{href:"#factories"}},[t._v("Factories")])])])]),a("p"),t._v(" "),a("h2",{attrs:{id:"factories"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#factories"}},[t._v("#")]),t._v(" Factories")]),t._v(" "),a("p",[t._v('While developing your application, you will likely want to "stub" a subscription record in your application\'s database so that calls to the '),a("code",[t._v("$billable->subscribed()")]),t._v(" method return "),a("code",[t._v("true")]),t._v(".")]),t._v(" "),a("p",[t._v('To accomplish this, you may add a "state" method to your billable model\'s '),a("a",{attrs:{href:"https://laravel.com/docs/database-testing#defining-model-factories",target:"_blank",rel:"noopener noreferrer"}},[t._v("factory class"),a("OutboundLink")],1),t._v(". Typically, this will be your application's "),a("code",[t._v("UserFactory")]),t._v(" class. Below you will find an example state method implementation; however, you are free to adjust this to your application's own needs:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Indicate that the user should have a subscription plan.\n *\n * @param string $planId\n * @return \\Illuminate\\Database\\Eloquent\\Factories\\Factory\n */")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$this")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("afterCreating")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$subscription")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscriptions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'default'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_id'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Str")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("random")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_status'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'active'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_price'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'quantity'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'ends_at'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$subscription")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("items")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_id'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Str")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("random")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_product'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Str")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("random")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_price'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'quantity'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Once you have define the state method, you may use it when creating models via your factory:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("factory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("withSubscription")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// true")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/49.52b310b3.js b/.vuepress/dist/assets/js/49.52b310b3.js new file mode 100644 index 0000000..2db1e90 --- /dev/null +++ b/.vuepress/dist/assets/js/49.52b310b3.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[49],{445:function(t,a,s){"use strict";s.r(a);var e=s(55),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"upgrade"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#upgrade"}},[t._v("#")]),t._v(" Upgrade")]),t._v(" "),s("p"),s("div",{staticClass:"table-of-contents"},[s("ul",[s("li",[s("a",{attrs:{href:"#upgrading-to-spark-stripe-2-0-from-1-x"}},[t._v("Upgrading to Spark (Stripe) 2.0 From 1.x")]),s("ul",[s("li",[s("a",{attrs:{href:"#minimum-versions"}},[t._v("Minimum Versions")])]),s("li",[s("a",{attrs:{href:"#stripe-api-version"}},[t._v("Stripe API Version")])]),s("li",[s("a",{attrs:{href:"#vatcalculator-v3"}},[t._v("VatCalculator v3")])]),s("li",[s("a",{attrs:{href:"#renaming-plans-to-prices"}},[t._v('Renaming "Plans" To Prices')])]),s("li",[s("a",{attrs:{href:"#new-payment-methods-support"}},[t._v("New Payment Methods Support")])]),s("li",[s("a",{attrs:{href:"#stripe-product-support"}},[t._v("Stripe Product Support")])])])]),s("li",[s("a",{attrs:{href:"#upgrading-to-spark-stripe-v1-0-5"}},[t._v("Upgrading To Spark (Stripe) v1.0.5")])])])]),s("p"),t._v(" "),s("h2",{attrs:{id:"upgrading-to-spark-stripe-2-0-from-1-x"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#upgrading-to-spark-stripe-2-0-from-1-x"}},[t._v("#")]),t._v(" Upgrading to Spark (Stripe) 2.0 From 1.x")]),t._v(" "),s("p",[t._v("Spark (Stripe) 2.0 primarily provides an upgrade from Cashier 12.x to Cashier 13.x. As such, in addition to the upgrade guide below, please consult the "),s("a",{attrs:{href:"https://github.com/laravel/cashier-stripe/blob/13.x/UPGRADE.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("Cashier 13 upgrade guide"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"minimum-versions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#minimum-versions"}},[t._v("#")]),t._v(" Minimum Versions")]),t._v(" "),s("p",[t._v("The following required dependency versions have been updated:")]),t._v(" "),s("ul",[s("li",[t._v("The minimum Cashier Stripe version is now v13.0")]),t._v(" "),s("li",[t._v("The minimum Laravel version is now v9.0")]),t._v(" "),s("li",[t._v("The minimum PHP version is now v8.0")]),t._v(" "),s("li",[t._v("The minimum Stripe SDK version is now v7.39")]),t._v(" "),s("li",[t._v("The minimum VatCalculator version is now v3.0")])]),t._v(" "),s("h3",{attrs:{id:"stripe-api-version"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#stripe-api-version"}},[t._v("#")]),t._v(" Stripe API Version")]),t._v(" "),s("p",[t._v("The default Stripe API version for Cashier 13.x is "),s("code",[t._v("2020-08-27")]),t._v(".")]),t._v(" "),s("p",[t._v("If you use the Stripe SDK directly, make sure to properly test your integration after updating.")]),t._v(" "),s("h4",{attrs:{id:"upgrading-your-stripe-webhook"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#upgrading-your-stripe-webhook"}},[t._v("#")]),t._v(" Upgrading Your Stripe Webhook")]),t._v(" "),s("p",[t._v("You should ensure your Stripe webhook operates on the same API version as Spark's underlying API version used by Cashier. To do so, you may use the "),s("code",[t._v("cashier:webhook")]),t._v(" command from your production environment to create a new webhook that matches Cashier's Stripe API version:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan cashier:webhook --disabled\n")])])]),s("p",[t._v("This will create a new webhook with the same Stripe API version as Cashier "),s("a",{attrs:{href:"https://dashboard.stripe.com/webhooks",target:"_blank",rel:"noopener noreferrer"}},[t._v("in your Stripe dashboard"),s("OutboundLink")],1),t._v(". The webhook will be immediately disabled so it doesn't interfere with your existing production application until you are ready to enable it. By default, the webhook will be created using the "),s("code",[t._v("APP_URL")]),t._v(" environment variable to determine the proper URL for your application. If you need to use a different URL, you can use the "),s("code",[t._v("--url")]),t._v(" flag when invoking the command:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("php artisan cashier:webhook --disabled --url "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"http://example.com/spark/webhook"')]),t._v("\n")])])]),s("p",[t._v("You may use the following upgrade checklist to properly enable to the new webhook:")]),t._v(" "),s("ol",[s("li",[t._v("If you have webhook signature verification enabled, disable it on production by temporarily removing the "),s("code",[t._v("STRIPE_WEBHOOK_SECRET")]),t._v(" environment variable.")]),t._v(" "),s("li",[t._v("Add any extra Stripe events your application requires to the new webhook in your Stripe dashboard.")]),t._v(" "),s("li",[t._v("Disable the old webhook in your Stripe dashboard.")]),t._v(" "),s("li",[t._v("Enable the new webhook in your Stripe dashboard.")]),t._v(" "),s("li",[t._v("Re-enable the new webhook secret by re-adding the "),s("code",[t._v("STRIPE_WEBHOOK_SECRET")]),t._v(" environment variable in production with the secret from the new webhook.")]),t._v(" "),s("li",[t._v("Remove the old webhook in your Stripe dashboard.")])]),t._v(" "),s("p",[t._v("After following this process, your new webhook will be active and ready to receive events.")]),t._v(" "),s("h3",{attrs:{id:"vatcalculator-v3"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#vatcalculator-v3"}},[t._v("#")]),t._v(" VatCalculator v3")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://github.com/driesvints/vat-calculator",target:"_blank",rel:"noopener noreferrer"}},[t._v("VatCalculator"),s("OutboundLink")],1),t._v(" was upgraded to its latest major version, v3. While there shouldn't be any breaking changes for Spark, you might want to review its "),s("a",{attrs:{href:"https://github.com/driesvints/vat-calculator/blob/3.x/UPGRADE.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("upgrade guide"),s("OutboundLink")],1),t._v(", specifically the section on "),s("a",{attrs:{href:"https://github.com/driesvints/vat-calculator/blob/3.x/UPGRADE.md#removed-countries",target:"_blank",rel:"noopener noreferrer"}},[t._v("removed countries"),s("OutboundLink")],1),t._v(" for tax calculations.")]),t._v(" "),s("h3",{attrs:{id:"renaming-plans-to-prices"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#renaming-plans-to-prices"}},[t._v("#")]),t._v(' Renaming "Plans" To Prices')]),t._v(" "),s("p",[t._v('To accommodate Stripe\'s phasing out of the "Plans" API, we\'ve made the choice to partially migrate away from the "Plans" terminology. Because of this, the '),s("code",[t._v("stripe_plan")]),t._v(" columns on the "),s("code",[t._v("subscriptions")]),t._v(" and "),s("code",[t._v("subscription_items")]),t._v(" tables have been renamed to "),s("code",[t._v("stripe_price")]),t._v(". You will need to write a migration to rename these columns:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("table")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscriptions'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Blueprint")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("renameColumn")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_plan'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_price'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("table")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscription_items'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Blueprint")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("renameColumn")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_plan'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_price'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("Running this migration requires you to "),s("a",{attrs:{href:"https://laravel.com/docs/migrations#renaming-columns",target:"_blank",rel:"noopener noreferrer"}},[t._v("install the "),s("code",[t._v("doctrine/dbal")]),t._v(" package"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"new-payment-methods-support"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#new-payment-methods-support"}},[t._v("#")]),t._v(" New Payment Methods Support")]),t._v(" "),s("p",[t._v("Cashier v13 supports new payment methods. Because of this, the "),s("code",[t._v("card")]),t._v(" columns in the database have been renamed to accommodate for all types of payment methods. You will need to write a migration to rename the billable model table's "),s("code",[t._v("card_brand")]),t._v(", "),s("code",[t._v("card_last_four")]),t._v(" and "),s("code",[t._v("card_expiration")]),t._v(" columns accordingly:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("table")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'users'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Blueprint")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("renameColumn")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'card_brand'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'pm_type'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("renameColumn")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'card_last_four'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'pm_last_four'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("renameColumn")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'card_expiration'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'pm_expiration'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("Running this migration requires you to "),s("a",{attrs:{href:"https://laravel.com/docs/migrations#renaming-columns",target:"_blank",rel:"noopener noreferrer"}},[t._v("install the "),s("code",[t._v("doctrine/dbal")]),t._v(" package"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"stripe-product-support"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#stripe-product-support"}},[t._v("#")]),t._v(" Stripe Product Support")]),t._v(" "),s("p",[t._v("PR: https://github.com/laravel/cashier-stripe/pull/1185")]),t._v(" "),s("p",[t._v("Cashier Stripe v13 includes support for inspecting Stripe Product identifiers. To provide support for this feature, a new "),s("code",[t._v("stripe_product")]),t._v(" column should be added to the "),s("code",[t._v("subscription_items")]),t._v(" table:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("table")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscription_items'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Blueprint")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token keyword type-declaration"}},[t._v("string")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_product'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("nullable")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("after")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[t._v("If you would like to make use of the new "),s("code",[t._v("onProduct")]),t._v(" & "),s("code",[t._v("subscribedToProduct")]),t._v(" methods on your billable model, you should ensure the records in the "),s("code",[t._v("subscription_items")]),t._v(" have their "),s("code",[t._v("stripe_product")]),t._v(" column filled with the correct Product ID from Stripe.")]),t._v(" "),s("h2",{attrs:{id:"upgrading-to-spark-stripe-v1-0-5"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#upgrading-to-spark-stripe-v1-0-5"}},[t._v("#")]),t._v(" Upgrading To Spark (Stripe) v1.0.5")]),t._v(" "),s("h4",{attrs:{id:"updating-the-configuration-file"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-configuration-file"}},[t._v("#")]),t._v(" Updating The Configuration File")]),t._v(" "),s("p",[t._v("Spark (Stripe) v1.0.5 introduces a new format for enabling features in the configuration file. To use the new format, add the following lines to your "),s("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Features")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Features::euVatCollection(['home-country' => 'BE']),")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Features::receiptEmails(['custom-addresses' => true]),")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Features")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("paymentNotificationEmails")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),s("p",[t._v("Next, uncomment the features you want to use in your application and remove the old corresponding configuration keys:")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("collects_eu_vat")])]),t._v(" "),s("li",[s("code",[t._v("sends_receipt_emails")])]),t._v(" "),s("li",[s("code",[t._v("sends_payment_notification_emails")])])]),t._v(" "),s("h4",{attrs:{id:"collecting-billing-email-addresses"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#collecting-billing-email-addresses"}},[t._v("#")]),t._v(" Collecting Billing Email Addresses")]),t._v(" "),s("p",[t._v("Spark (Stripe) 1.0.5 introduces the ability to email receipts to a custom billing address that the customer provides. This is typically used to email receipts directly to an accountant.")]),t._v(" "),s("p",[t._v("To support this feature, you need to create a new migration in your application and add the following schema modification in the migration's "),s("code",[t._v("up()")]),t._v(" method:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("up")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("hasColumn")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'users'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'receipt_emails'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("table")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'users'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Blueprint")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("text")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'receipt_emails'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("after")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("Make sure to run the migration against the table that corresponds to your billable model.")]),t._v(" "),s("p",[t._v("To enable the feature, uncomment the "),s("code",[t._v("Features::receiptEmails()")]),t._v(" line in your "),s("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),s("div",{staticClass:"language-php extra-class"},[s("pre",{pre:!0,attrs:{class:"language-php"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Features::euVatCollection(['home-country' => 'BE']),")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Features")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("receiptEmails")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'custom-addresses'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Features")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("paymentNotificationEmailsSending")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/49.72f352fe.js b/.vuepress/dist/assets/js/49.72f352fe.js deleted file mode 100644 index b7f6134..0000000 --- a/.vuepress/dist/assets/js/49.72f352fe.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[49],{446:function(t,s,a){"use strict";a.r(s);var e=a(55),n=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"upgrade"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#upgrade"}},[t._v("#")]),t._v(" Upgrade")]),t._v(" "),a("p"),a("div",{staticClass:"table-of-contents"},[a("ul",[a("li",[a("a",{attrs:{href:"#upgrading-to-spark-stripe-v2-0-from-v1-x"}},[t._v("Upgrading to Spark-Stripe v2.0 From v1.x")]),a("ul",[a("li",[a("a",{attrs:{href:"#minimum-versions"}},[t._v("Minimum Versions")])]),a("li",[a("a",{attrs:{href:"#stripe-api-version"}},[t._v("Stripe API Version")])]),a("li",[a("a",{attrs:{href:"#renaming-plans-to-prices"}},[t._v('Renaming "Plans" To Prices')])]),a("li",[a("a",{attrs:{href:"#new-payment-methods-support"}},[t._v("New Payment Methods Support")])]),a("li",[a("a",{attrs:{href:"#stripe-product-support"}},[t._v("Stripe Product Support")])])])]),a("li",[a("a",{attrs:{href:"#upgrading-to-spark-stripe-v1-0-5"}},[t._v("Upgrading to Spark-Stripe v1.0.5")])])])]),a("p"),t._v(" "),a("h2",{attrs:{id:"upgrading-to-spark-stripe-v2-0-from-v1-x"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#upgrading-to-spark-stripe-v2-0-from-v1-x"}},[t._v("#")]),t._v(" Upgrading to Spark-Stripe v2.0 From v1.x")]),t._v(" "),a("p",[t._v("In addition to the upgrade guide below, please reference "),a("a",{attrs:{href:"https://github.com/laravel/cashier-stripe/blob/13.x/UPGRADE.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("the Cashier v13 upgrade guide "),a("OutboundLink")],1),t._v("as well.")]),t._v(" "),a("h3",{attrs:{id:"minimum-versions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#minimum-versions"}},[t._v("#")]),t._v(" Minimum Versions")]),t._v(" "),a("p",[t._v("The following required dependency versions have been updated:")]),t._v(" "),a("ul",[a("li",[t._v("The minimum Cashier Stripe version is now v13.0")]),t._v(" "),a("li",[t._v("The minimum Laravel version is now v9.0")]),t._v(" "),a("li",[t._v("The minimum PHP version is now v8.0")]),t._v(" "),a("li",[t._v("The minimum Stripe SDK version is now v7.39")])]),t._v(" "),a("h3",{attrs:{id:"stripe-api-version"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#stripe-api-version"}},[t._v("#")]),t._v(" Stripe API Version")]),t._v(" "),a("p",[t._v("The default Stripe API version for Cashier 13.x will be "),a("code",[t._v("2020-08-27")]),t._v(". If this is the latest Stripe API version at the time that you're upgrading to this Cashier version then it's also recommended that you upgrade your own Stripe API version settings "),a("a",{attrs:{href:"https://dashboard.stripe.com/developers",target:"_blank",rel:"noopener noreferrer"}},[t._v("in your Stripe dashboard"),a("OutboundLink")],1),t._v(" to this version after deploying the Cashier upgrade. If this is no longer the latest Stripe API version, we recommend you do not modify your Stripe API version settings.")]),t._v(" "),a("p",[t._v("If you use the Stripe SDK directly, make sure to properly test your integration after updating.")]),t._v(" "),a("h4",{attrs:{id:"upgrading-your-webhook"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#upgrading-your-webhook"}},[t._v("#")]),t._v(" Upgrading Your Webhook")]),t._v(" "),a("p",[t._v("You should ensure your webhook operates on the same API version as Cashier. To do so, you may use the "),a("code",[t._v("cashier:webhook")]),t._v(" command from your production environment to create a new webhook that matches Cashier's Stripe API version:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[t._v("php artisan cashier:webhook --disabled\n")])])]),a("p",[t._v("This will create a new webhook with the same Stripe API version as Cashier "),a("a",{attrs:{href:"https://dashboard.stripe.com/webhooks",target:"_blank",rel:"noopener noreferrer"}},[t._v("in your Stripe dashboard"),a("OutboundLink")],1),t._v(". The webhook will be immediately disabled so it doesn't interfere with your existing production application until you are ready to enable it. By default, the webhook will be created using the "),a("code",[t._v("APP_URL")]),t._v(" environment variable to determine the proper URL for your application. If you need to use a different URL, you can use the "),a("code",[t._v("--url")]),t._v(" flag when invoking the command:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[t._v("php artisan cashier:webhook --disabled --url "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"http://example.com/spark/webhook"')]),t._v("\n")])])]),a("p",[t._v("You may use the following upgrade checklist to properly enable to the new webhook:")]),t._v(" "),a("ol",[a("li",[t._v("If you have webhook signature verification enabled, disable it on production by temporarily removing the "),a("code",[t._v("STRIPE_WEBHOOK_SECRET")]),t._v(" environment variable.")]),t._v(" "),a("li",[t._v("Add any extra Stripe events your application requires to the new webhook in your Stripe dashboard.")]),t._v(" "),a("li",[t._v("Disable the old webhook in your Stripe dashboard.")]),t._v(" "),a("li",[t._v("Enable the new webhook in your Stripe dashboard.")]),t._v(" "),a("li",[t._v("Re-enable the new webhook secret by re-adding the "),a("code",[t._v("STRIPE_WEBHOOK_SECRET")]),t._v(" environment variable in production with the secret from the new webhook.")]),t._v(" "),a("li",[t._v("Remove the old webhook in your Stripe dashboard.")])]),t._v(" "),a("p",[t._v("After following this process, your new webhook will be active and ready to receive events.")]),t._v(" "),a("h3",{attrs:{id:"renaming-plans-to-prices"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#renaming-plans-to-prices"}},[t._v("#")]),t._v(' Renaming "Plans" To Prices')]),t._v(" "),a("p",[t._v('To accommodate Stripe\'s phasing out of the "Plans" API, we\'ve made the choice to partially migrate away from the "Plans" terminology. Because of this, the '),a("code",[t._v("stripe_plan")]),t._v(" columns on the "),a("code",[t._v("subscriptions")]),t._v(" and "),a("code",[t._v("subscription_items")]),t._v(" tables have been renamed to "),a("code",[t._v("stripe_price")]),t._v(". You will need to write a migration to rename these columns:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("table")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscriptions'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Blueprint")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("renameColumn")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_plan'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_price'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("table")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscription_items'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Blueprint")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("renameColumn")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_plan'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_price'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Running this migration requires you to "),a("a",{attrs:{href:"https://laravel.com/docs/migrations#renaming-columns",target:"_blank",rel:"noopener noreferrer"}},[t._v("install the "),a("code",[t._v("doctrine/dbal")]),t._v(" package"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("h3",{attrs:{id:"new-payment-methods-support"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#new-payment-methods-support"}},[t._v("#")]),t._v(" New Payment Methods Support")]),t._v(" "),a("p",[t._v("Cashier v13 supports new payment methods. Because of this, the "),a("code",[t._v("card")]),t._v(" columns in the database have been renamed to accommodate for all types of payment methods. You will need to write a migration to rename the billable model table's "),a("code",[t._v("card_brand")]),t._v(", "),a("code",[t._v("card_last_four")]),t._v(" and "),a("code",[t._v("card_expiration")]),t._v(" columns accordingly:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("table")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'users'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Blueprint")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("renameColumn")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'card_brand'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'pm_type'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("renameColumn")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'card_last_four'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'pm_last_four'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("renameColumn")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'card_expiration'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'pm_expiration'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Running this migration requires you to "),a("a",{attrs:{href:"https://laravel.com/docs/migrations#renaming-columns",target:"_blank",rel:"noopener noreferrer"}},[t._v("install the "),a("code",[t._v("doctrine/dbal")]),t._v(" package"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("h3",{attrs:{id:"stripe-product-support"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#stripe-product-support"}},[t._v("#")]),t._v(" Stripe Product Support")]),t._v(" "),a("p",[t._v("PR: https://github.com/laravel/cashier-stripe/pull/1185")]),t._v(" "),a("p",[t._v("Cashier Stripe v13 comes with support for checking Stripe Product identifiers. To provide support for this feature, a new "),a("code",[t._v("stripe_product")]),t._v(" column should be added to the "),a("code",[t._v("subscription_items")]),t._v(" table:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("table")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'subscription_items'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Blueprint")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token keyword type-declaration"}},[t._v("string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_product'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("nullable")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("after")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("If you'd like to make use of the new "),a("code",[t._v("onProduct")]),t._v(" & "),a("code",[t._v("subscribedToProduct")]),t._v(" methods on your billable model, you should ensure the records in the "),a("code",[t._v("subscription_items")]),t._v(" have their "),a("code",[t._v("stripe_product")]),t._v(" column filled with the correct Product ID from Stripe.")]),t._v(" "),a("h2",{attrs:{id:"upgrading-to-spark-stripe-v1-0-5"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#upgrading-to-spark-stripe-v1-0-5"}},[t._v("#")]),t._v(" Upgrading to Spark-Stripe v1.0.5")]),t._v(" "),a("h4",{attrs:{id:"updating-the-configuration-file"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#updating-the-configuration-file"}},[t._v("#")]),t._v(" Updating The Configuration File")]),t._v(" "),a("p",[t._v("Spark-Stripe v1.0.5 introduces a new format for enabling features in the configuration file. To use the new format, add the following lines to your "),a("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Features")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Features::euVatCollection(['home-country' => 'BE']),")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Features::receiptEmails(['custom-addresses' => true]),")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Features")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("paymentNotificationEmails")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),a("p",[t._v("Next, uncomment the features you want to use in your application and remove the old corresponding configuration keys:")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("collects_eu_vat")])]),t._v(" "),a("li",[a("code",[t._v("sends_receipt_emails")])]),t._v(" "),a("li",[a("code",[t._v("sends_payment_notification_emails")])])]),t._v(" "),a("h4",{attrs:{id:"collecting-billing-email-addresses"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#collecting-billing-email-addresses"}},[t._v("#")]),t._v(" Collecting Billing Email Addresses")]),t._v(" "),a("p",[t._v("Spark-Stripe v1.0.5 introduces the ability to email receipts to a custom billing address that the customer provides. This is typically used to email receipts directly to an accountant.")]),t._v(" "),a("p",[t._v("To support this feature, you need to create a new migration in your application and add the following schema modification in the migration's "),a("code",[t._v("up()")]),t._v(" method:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("up")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("hasColumn")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'users'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'receipt_emails'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Schema")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("table")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'users'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Blueprint")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$table")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("text")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'receipt_emails'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("after")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'stripe_id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Make sure to run the migration against the table that corresponds to your billable model.")]),t._v(" "),a("p",[t._v("To enable the feature, uncomment the "),a("code",[t._v("Features::receiptEmails()")]),t._v(" line in your "),a("code",[t._v("config/spark.php")]),t._v(" configuration file:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Features::euVatCollection(['home-country' => 'BE']),")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Features")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("receiptEmails")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'custom-addresses'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Features")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("paymentNotificationEmailsSending")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/5.5d3848bb.js b/.vuepress/dist/assets/js/5.9e9fc063.js similarity index 89% rename from .vuepress/dist/assets/js/5.5d3848bb.js rename to .vuepress/dist/assets/js/5.9e9fc063.js index 6cfb577..e6cd145 100644 --- a/.vuepress/dist/assets/js/5.5d3848bb.js +++ b/.vuepress/dist/assets/js/5.9e9fc063.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{372:function(e,t,a){},399:function(e,t,a){"use strict";a(372)},403:function(e,t,a){"use strict";a.r(t);a(83),a(56),a(9),a(115),a(116);var o={name:"CodeGroup",data:function(){return{codeTabs:[],activeCodeTabIndex:-1}},watch:{activeCodeTabIndex:function(e){this.activateCodeTab(e)}},mounted:function(){this.loadTabs()},methods:{changeCodeTab:function(e){this.activeCodeTabIndex=e},loadTabs:function(){var e=this;this.codeTabs=(this.$slots.default||[]).filter((function(e){return Boolean(e.componentOptions)})).map((function(t,a){return""===t.componentOptions.propsData.active&&(e.activeCodeTabIndex=a),{title:t.componentOptions.propsData.title,elm:t.elm}})),-1===this.activeCodeTabIndex&&this.codeTabs.length>0&&(this.activeCodeTabIndex=0),this.activateCodeTab(0)},activateCodeTab:function(e){this.codeTabs.forEach((function(e){e.elm&&e.elm.classList.remove("theme-code-block__active")})),this.codeTabs[e].elm&&this.codeTabs[e].elm.classList.add("theme-code-block__active")}}},n=(a(399),a(55)),c=Object(n.a)(o,(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ClientOnly",[a("div",{staticClass:"theme-code-group"},[a("div",{staticClass:"theme-code-group__nav"},[a("ul",{staticClass:"theme-code-group__ul"},e._l(e.codeTabs,(function(t,o){return a("li",{key:t.title,staticClass:"theme-code-group__li"},[a("button",{staticClass:"theme-code-group__nav-tab",class:{"theme-code-group__nav-tab-active":o===e.activeCodeTabIndex},on:{click:function(t){return e.changeCodeTab(o)}}},[e._v("\n "+e._s(t.title)+"\n ")])])})),0)]),e._v(" "),e._t("default"),e._v(" "),e.codeTabs.length<1?a("pre",{staticClass:"pre-blank"},[e._v("// Make sure to add code blocks to your code group")]):e._e()],2)])}),[],!1,null,"deefee04",null);t.default=c.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{373:function(e,t,a){},400:function(e,t,a){"use strict";a(373)},404:function(e,t,a){"use strict";a.r(t);a(83),a(56),a(9),a(115),a(116);var o={name:"CodeGroup",data:function(){return{codeTabs:[],activeCodeTabIndex:-1}},watch:{activeCodeTabIndex:function(e){this.activateCodeTab(e)}},mounted:function(){this.loadTabs()},methods:{changeCodeTab:function(e){this.activeCodeTabIndex=e},loadTabs:function(){var e=this;this.codeTabs=(this.$slots.default||[]).filter((function(e){return Boolean(e.componentOptions)})).map((function(t,a){return""===t.componentOptions.propsData.active&&(e.activeCodeTabIndex=a),{title:t.componentOptions.propsData.title,elm:t.elm}})),-1===this.activeCodeTabIndex&&this.codeTabs.length>0&&(this.activeCodeTabIndex=0),this.activateCodeTab(0)},activateCodeTab:function(e){this.codeTabs.forEach((function(e){e.elm&&e.elm.classList.remove("theme-code-block__active")})),this.codeTabs[e].elm&&this.codeTabs[e].elm.classList.add("theme-code-block__active")}}},n=(a(400),a(55)),c=Object(n.a)(o,(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ClientOnly",[a("div",{staticClass:"theme-code-group"},[a("div",{staticClass:"theme-code-group__nav"},[a("ul",{staticClass:"theme-code-group__ul"},e._l(e.codeTabs,(function(t,o){return a("li",{key:t.title,staticClass:"theme-code-group__li"},[a("button",{staticClass:"theme-code-group__nav-tab",class:{"theme-code-group__nav-tab-active":o===e.activeCodeTabIndex},on:{click:function(t){return e.changeCodeTab(o)}}},[e._v("\n "+e._s(t.title)+"\n ")])])})),0)]),e._v(" "),e._t("default"),e._v(" "),e.codeTabs.length<1?a("pre",{staticClass:"pre-blank"},[e._v("// Make sure to add code blocks to your code group")]):e._e()],2)])}),[],!1,null,"deefee04",null);t.default=c.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/30.d6a51d12.js b/.vuepress/dist/assets/js/50.4891d2a2.js similarity index 83% rename from .vuepress/dist/assets/js/30.d6a51d12.js rename to .vuepress/dist/assets/js/50.4891d2a2.js index d95f2ab..db3dbc2 100644 --- a/.vuepress/dist/assets/js/30.d6a51d12.js +++ b/.vuepress/dist/assets/js/50.4891d2a2.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{427:function(t,e,n){"use strict";n.r(e);var s=n(55),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("meta",{attrs:{"http-equiv":"refresh",content:"0;url=/docs/2.x/introduction.html"}})])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[50],{444:function(t,e,n){"use strict";n.r(e);var s=n(55),r=Object(s.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("meta",{attrs:{"http-equiv":"refresh",content:"0;url=/docs/2.x/introduction.html"}})])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/51.ca79f3f4.js b/.vuepress/dist/assets/js/51.16efd940.js similarity index 99% rename from .vuepress/dist/assets/js/51.ca79f3f4.js rename to .vuepress/dist/assets/js/51.16efd940.js index 50ddbbd..9a3e148 100644 --- a/.vuepress/dist/assets/js/51.ca79f3f4.js +++ b/.vuepress/dist/assets/js/51.16efd940.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[51],{448:function(t,e,a){"use strict";a.r(e);var s=a(55),n=Object(s.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h2",{attrs:{id:"formatting-examples"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#formatting-examples"}},[t._v("#")]),t._v(" Formatting Examples")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("Did you know?")]),t._v(" "),a("p",[t._v("Laravel now offers Horizon, a beautiful dashboard and configuration system for your Redis powered queues. Check out the full "),a("a",{attrs:{href:"/docs/%7B%7Bversion%7D%7D/horizon"}},[t._v("Horizon documentation")]),t._v(" for more information.")])]),t._v(" "),a("div",{staticClass:"custom-block warning"},[a("p",{staticClass:"custom-block-title"},[t._v("Something to keep in mind")]),t._v(" "),a("p",[t._v("Laravel now offers Horizon, a beautiful dashboard and configuration system for your Redis powered queues. Check out the full "),a("a",{attrs:{href:"/docs/%7B%7Bversion%7D%7D/horizon"}},[t._v("Horizon documentation")]),t._v(" for more information.")])]),t._v(" "),a("div",{staticClass:"custom-block danger"},[a("p",{staticClass:"custom-block-title"},[t._v("Be Careful!")]),t._v(" "),a("p",[t._v("Laravel now offers Horizon, a beautiful dashboard and configuration system for your Redis powered queues. Check out the full "),a("a",{attrs:{href:"/docs/%7B%7Bversion%7D%7D/horizon"}},[t._v("Horizon documentation")]),t._v(" for more information.")])]),t._v(" "),a("p",[t._v("Laravel queues provide a unified API across a variety of different queue backends, such as Beanstalk, Amazon SQS, Redis, or even a relational database. Queues allow you to defer the processing of a time consuming task, such as sending an email, until a later time. Deferring these time consuming tasks drastically speeds up web requests to your application.")]),t._v(" "),a("p",[t._v("The queue configuration file is stored in "),a("code",[t._v("config/queue.php")]),t._v(". In this file you will find connection configurations for each of the queue drivers that are included with the framework, which includes a database, "),a("a",{attrs:{href:"https://kr.github.io/beanstalkd/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Beanstalkd"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://aws.amazon.com/sqs/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Amazon SQS"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://redis.io",target:"_blank",rel:"noopener noreferrer"}},[t._v("Redis"),a("OutboundLink")],1),t._v(", and a synchronous driver that will execute jobs immediately (for local use). A "),a("code",[t._v("null")]),t._v(" queue driver is also included which discards queued jobs.")]),t._v(" "),a("h3",{attrs:{id:"sub-sub-section"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#sub-sub-section"}},[t._v("#")]),t._v(" Sub Sub Section")]),t._v(" "),a("p",[t._v('Before getting started with Laravel queues, it is important to understand the distinction between "connections" and "queues". In your '),a("code",[t._v("config/queue.php")]),t._v(" configuration file, there is a "),a("code",[t._v("connections")]),t._v(' configuration option. This option defines a particular connection to a backend service such as Amazon SQS, Beanstalk, or Redis. However, any given queue connection may have multiple "queues" which may be thought of as different stacks or piles of queued jobs.')]),t._v(" "),a("p",[t._v("Note that each connection configuration example in the "),a("code",[t._v("queue")]),t._v(" configuration file contains a "),a("code",[t._v("queue")]),t._v(" attribute. This is the default queue that jobs will be dispatched to when they are sent to a given connection. In other words, if you dispatch a job without explicitly defining which queue it should be dispatched to, the job will be placed on the queue that is defined in the "),a("code",[t._v("queue")]),t._v(" attribute of the connection configuration:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// This job is sent to the default queue...")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Job")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("dispatch")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// This job is sent to the "emails" queue...')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Job")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("dispatch")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("onQueue")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'emails'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("h4",{attrs:{id:"_4th-level"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4th-level"}},[t._v("#")]),t._v(" 4th Level")]),t._v(" "),a("p",[t._v("In order to use the "),a("code",[t._v("database")]),t._v(" queue driver, you will need a database table to hold the jobs. To generate a migration that creates this table, run the "),a("code",[t._v("queue:table")]),t._v(" Artisan command. Once the migration has been created, you may migrate your database using the "),a("code",[t._v("migrate")]),t._v(" command:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[t._v("php artisan queue:table\n\nphp artisan migrate\n")])])]),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token php language-php"}},[a("span",{pre:!0,attrs:{class:"token delimiter important"}},[t._v("connectionName")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// $event->job")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// $event->job->payload()")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Queue")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("after")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("JobProcessed")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// $event->connectionName")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// $event->job")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// $event->job->payload()")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Register the service provider.\n *\n * @return void\n */")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[51],{449:function(t,e,a){"use strict";a.r(e);var s=a(55),n=Object(s.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h2",{attrs:{id:"formatting-examples"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#formatting-examples"}},[t._v("#")]),t._v(" Formatting Examples")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("Did you know?")]),t._v(" "),a("p",[t._v("Laravel now offers Horizon, a beautiful dashboard and configuration system for your Redis powered queues. Check out the full "),a("a",{attrs:{href:"/docs/%7B%7Bversion%7D%7D/horizon"}},[t._v("Horizon documentation")]),t._v(" for more information.")])]),t._v(" "),a("div",{staticClass:"custom-block warning"},[a("p",{staticClass:"custom-block-title"},[t._v("Something to keep in mind")]),t._v(" "),a("p",[t._v("Laravel now offers Horizon, a beautiful dashboard and configuration system for your Redis powered queues. Check out the full "),a("a",{attrs:{href:"/docs/%7B%7Bversion%7D%7D/horizon"}},[t._v("Horizon documentation")]),t._v(" for more information.")])]),t._v(" "),a("div",{staticClass:"custom-block danger"},[a("p",{staticClass:"custom-block-title"},[t._v("Be Careful!")]),t._v(" "),a("p",[t._v("Laravel now offers Horizon, a beautiful dashboard and configuration system for your Redis powered queues. Check out the full "),a("a",{attrs:{href:"/docs/%7B%7Bversion%7D%7D/horizon"}},[t._v("Horizon documentation")]),t._v(" for more information.")])]),t._v(" "),a("p",[t._v("Laravel queues provide a unified API across a variety of different queue backends, such as Beanstalk, Amazon SQS, Redis, or even a relational database. Queues allow you to defer the processing of a time consuming task, such as sending an email, until a later time. Deferring these time consuming tasks drastically speeds up web requests to your application.")]),t._v(" "),a("p",[t._v("The queue configuration file is stored in "),a("code",[t._v("config/queue.php")]),t._v(". In this file you will find connection configurations for each of the queue drivers that are included with the framework, which includes a database, "),a("a",{attrs:{href:"https://kr.github.io/beanstalkd/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Beanstalkd"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://aws.amazon.com/sqs/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Amazon SQS"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://redis.io",target:"_blank",rel:"noopener noreferrer"}},[t._v("Redis"),a("OutboundLink")],1),t._v(", and a synchronous driver that will execute jobs immediately (for local use). A "),a("code",[t._v("null")]),t._v(" queue driver is also included which discards queued jobs.")]),t._v(" "),a("h3",{attrs:{id:"sub-sub-section"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#sub-sub-section"}},[t._v("#")]),t._v(" Sub Sub Section")]),t._v(" "),a("p",[t._v('Before getting started with Laravel queues, it is important to understand the distinction between "connections" and "queues". In your '),a("code",[t._v("config/queue.php")]),t._v(" configuration file, there is a "),a("code",[t._v("connections")]),t._v(' configuration option. This option defines a particular connection to a backend service such as Amazon SQS, Beanstalk, or Redis. However, any given queue connection may have multiple "queues" which may be thought of as different stacks or piles of queued jobs.')]),t._v(" "),a("p",[t._v("Note that each connection configuration example in the "),a("code",[t._v("queue")]),t._v(" configuration file contains a "),a("code",[t._v("queue")]),t._v(" attribute. This is the default queue that jobs will be dispatched to when they are sent to a given connection. In other words, if you dispatch a job without explicitly defining which queue it should be dispatched to, the job will be placed on the queue that is defined in the "),a("code",[t._v("queue")]),t._v(" attribute of the connection configuration:")]),t._v(" "),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// This job is sent to the default queue...")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Job")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("dispatch")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// This job is sent to the "emails" queue...')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Job")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("dispatch")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("onQueue")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'emails'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("h4",{attrs:{id:"_4th-level"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4th-level"}},[t._v("#")]),t._v(" 4th Level")]),t._v(" "),a("p",[t._v("In order to use the "),a("code",[t._v("database")]),t._v(" queue driver, you will need a database table to hold the jobs. To generate a migration that creates this table, run the "),a("code",[t._v("queue:table")]),t._v(" Artisan command. Once the migration has been created, you may migrate your database using the "),a("code",[t._v("migrate")]),t._v(" command:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[t._v("php artisan queue:table\n\nphp artisan migrate\n")])])]),a("div",{staticClass:"language-php extra-class"},[a("pre",{pre:!0,attrs:{class:"language-php"}},[a("code",[a("span",{pre:!0,attrs:{class:"token php language-php"}},[a("span",{pre:!0,attrs:{class:"token delimiter important"}},[t._v("connectionName")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// $event->job")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// $event->job->payload()")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Queue")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("after")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("JobProcessed")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// $event->connectionName")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// $event->job")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// $event->job->payload()")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * Register the service provider.\n *\n * @return void\n */")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/6.6e39d20d.js b/.vuepress/dist/assets/js/6.78edb7c1.js similarity index 99% rename from .vuepress/dist/assets/js/6.6e39d20d.js rename to .vuepress/dist/assets/js/6.78edb7c1.js index 08ce538..571e43c 100644 --- a/.vuepress/dist/assets/js/6.6e39d20d.js +++ b/.vuepress/dist/assets/js/6.78edb7c1.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{347:function(t,a,s){t.exports=s.p+"assets/img/incentive.f515e51f.png"},413:function(t,a,s){"use strict";s.r(a);var n=s(55),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,n=t._self._c||a;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#plans"}},[t._v("#")]),t._v(" Plans")]),t._v(" "),n("p"),n("div",{staticClass:"table-of-contents"},[n("ul",[n("li",[n("a",{attrs:{href:"#defining-payment-plans"}},[t._v("Defining Payment Plans")])]),n("li",[n("a",{attrs:{href:"#trial-periods"}},[t._v("Trial Periods")])]),n("li",[n("a",{attrs:{href:"#determining-plan-eligibility"}},[t._v("Determining Plan Eligibility")])]),n("li",[n("a",{attrs:{href:"#per-seat-billing-plans"}},[t._v("Per-Seat Billing Plans")]),n("ul",[n("li",[n("a",{attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("Incrementing / Decrementing The Seat Count")])])])]),n("li",[n("a",{attrs:{href:"#determining-subscription-status"}},[t._v("Determining Subscription Status")])]),n("li",[n("a",{attrs:{href:"#defining-plan-incentive-text"}},[t._v("Defining Plan Incentive Text")])]),n("li",[n("a",{attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("Access A Billable's Spark Plan")])]),n("li",[n("a",{attrs:{href:"#archiving-plans"}},[t._v("Archiving Plans")])]),n("li",[n("a",{attrs:{href:"#account-deletion"}},[t._v("Account Deletion")])])])]),n("p"),t._v(" "),n("h2",{attrs:{id:"defining-payment-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-payment-plans"}},[t._v("#")]),t._v(" Defining Payment Plans")]),t._v(" "),n("p",[n("strong",[t._v("For more information on defining payment plans for your application, please consult the "),n("RouterLink",{attrs:{to:"/1.x/spark-paddle/configuration.html#defining-subscription-plans"}},[t._v("plan configuration documentation")]),t._v(".")],1)]),t._v(" "),n("h2",{attrs:{id:"trial-periods"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#trial-periods"}},[t._v("#")]),t._v(" Trial Periods")]),t._v(" "),n("p",[t._v("By default, the plan configuration in your application's "),n("code",[t._v("config/spark.php")]),t._v(" configuration file contains a "),n("code",[t._v("trial_days")]),t._v(" option with a value of "),n("code",[t._v("5")]),t._v(". This configuration option determines the amount of time the user is allowed to use your application during their free trial period. You are free to modify this configuration value based on your application's needs.")]),t._v(" "),n("p",[t._v("In practical terms, this configuration option simply determines when the "),n("code",[t._v("onTrial")]),t._v(" method of the billable model will begin returning "),n("code",[t._v("false")]),t._v(" instead of "),n("code",[t._v("true")]),t._v(":")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Auth")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("onTrial")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user is still within their trial period...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("div",{staticClass:"custom-block danger"},[n("p",{staticClass:"custom-block-title"},[t._v("Paddle Trials")]),t._v(" "),n("p",[t._v("Because Paddle does not allow plan quantity changes during trial periods, the Paddle edition of Spark does not support requiring a credit card up front when beginning a trial. All trial periods are started without a credit card or payment method provided up front during the user's initial registration process.")]),t._v(" "),n("p",[n("strong",[t._v("Therefore, you may assign each subscription plan zero trial days when configuring subscription plans in your Paddle dashboard.")])])]),t._v(" "),n("h2",{attrs:{id:"determining-plan-eligibility"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-plan-eligibility"}},[t._v("#")]),t._v(" Determining Plan Eligibility")]),t._v(" "),n("p",[t._v("Sometimes, you may wish to place limitations on a particular billing plan. For example, a project management application might limit users on a particular billing plan to a maximum of 10 projects, while a higher priced plan might allow the creation of up to 20 projects.")]),t._v(" "),n("p",[t._v("If you choose to take this approach to billing, you will need to instruct Spark how to determine if a given billable model is eligible to be placed on a particular billing plan. You may accomplish this by modifying the "),n("code",[t._v("checkPlanEligibility")]),t._v(" callback registered within your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class. This callback will be invoked when a billable model attempts to subscribe to or switch to a new subscription plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Validation"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkPlanEligibility")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Plan")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("name")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Basic'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("throw")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("withMessages")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plan'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'You have too many projects for the selected plan.'")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"per-seat-billing-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#per-seat-billing-plans"}},[t._v("#")]),t._v(" Per-Seat Billing Plans")]),t._v(" "),n("p",[t._v('Some applications charge users per "seat" instead of a fixed monthly price. For example, a project management application might charge $10 monthly '),n("strong",[t._v("per project")]),t._v(" such that if a user managed five projects they would be billed $50 monthly.")]),t._v(" "),n("p",[t._v("If your application will be using per-seat billing, you will likely define a single, monthly plan in your application's "),n("code",[t._v("config/spark.php")]),t._v(' configuration file. In addition, you will need to instruct Spark how to calculate the current number of "seats" a billable model is currently using.')]),t._v(" "),n("div",{staticClass:"custom-block danger"},[n("p",{staticClass:"custom-block-title"},[t._v("Enabling Plan Quantity")]),t._v(" "),n("p",[t._v('While creating your subscription plans in Paddle\'s dashboard, make sure you select "Enable quantity". Otherwise, Paddle will ignore any quantity sent by Spark for per-seat billing.')])]),t._v(" "),n("p",[t._v('You may instruct Spark how to calculate the current number of "seats" a billable model is currently using via the '),n("code",[t._v("chargePerSeat")]),t._v(" method when configuring a billable model. Typically, this method should be called within the "),n("code",[t._v("boot")]),t._v(" method of your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("chargePerSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'project'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[t._v("The first argument accepted by the "),n("code",[t._v("chargePerSeat")]),t._v(' method is the term that your application uses to refer to a "seat". In the case of a project management application, this would be a "project". The second argument given to the '),n("code",[t._v("chargePerSeat")]),t._v(' method should be a closure that accepts the billable model and returns the current number of "seats" occupied by that model.')]),t._v(" "),n("p",[t._v("After configuring per-seat billing, Spark will automatically update the wording within your application's billing portal to inform users that billing is calculated on a per-seat basis.")]),t._v(" "),n("h3",{attrs:{id:"incrementing-decrementing-the-seat-count"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("#")]),t._v(" Incrementing / Decrementing The Seat Count")]),t._v(" "),n("p",[t._v("The "),n("code",[t._v("chargePerSeat")]),t._v(" callback that was explained above will inform Spark of the current seat count that should be used when a customer initiates a subscription. However, you still need to inform Spark when to add or remove a seat when a user is using your application. For example, if building a project management application that bills per project, you would need to inform Spark when a user creates or deletes a project. You can accomplish this by calling the "),n("code",[t._v("addSeat")]),t._v(" and "),n("code",[t._v("removeSeat")]),t._v(" method:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("addSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("removeSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"determining-subscription-status"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-subscription-status"}},[t._v("#")]),t._v(" Determining Subscription Status")]),t._v(" "),n("p",[t._v("While building your application, you will often need to inspect a user's subscription status and plan to determine if they are allowed to perform a given action. For example, you may not want to let a user create a project if they are subscribed to a billing plan that only allows a specific number of projects to be created. First, you should review the "),n("RouterLink",{attrs:{to:"/1.x/spark-paddle/middleware.html"}},[t._v("subscription verification middleware")]),t._v(" provided by Spark.")],1),t._v(" "),n("p",[t._v("Additionally, you may always manually inspect a billable model's subscription status using the "),n("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),n("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user has an active subscription...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribedToPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user has a subscription to a plan with a Paddle plan ID of 1000...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"defining-plan-incentive-text"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-plan-incentive-text"}},[t._v("#")]),t._v(" Defining Plan Incentive Text")]),t._v(" "),n("p",[t._v('Spark allows you to define plan "incentive" text to display to your users. For example, you may wish to display the amount saved by choosing to use a yearly plan vs. a monthly plan. Incentive text is shown in the top right corner of the plan\'s card:')]),t._v(" "),n("p",[n("img",{attrs:{src:s(347),alt:"Incentive text example"}})]),t._v(" "),n("p",[t._v("To define incentive text, you may add "),n("code",[t._v("monthly_incentive")]),t._v(" and / or "),n("code",[t._v("yearly_incentive")]),t._v(" configuration options to your plan definition:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_MONTHLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_YEARLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1001")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_incentive'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Save 10%'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 1'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 2'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 3'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"access-a-billable-s-spark-plan"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("#")]),t._v(" Access A Billable's Spark Plan")]),t._v(" "),n("p",[t._v("Sometimes you may wish to access the Spark plan instance for a given billable in order to determine what options are available to the plan. For example, if your plan definition contains the following:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_MONTHLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_YEARLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1001")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'options'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("p",[t._v("You may access the plan and options like so:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$canCreateBackups")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("options")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("??")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("false")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"archiving-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#archiving-plans"}},[t._v("#")]),t._v(" Archiving Plans")]),t._v(" "),n("p",[t._v('If you plan to "archive" or retire a particular plan for your application, you should add the '),n("code",[t._v("archived")]),t._v(" configuration option to the plan's configuration array. You should not completely remove the plan's configuration if existing users of your application that have already subscribed to the plan will be allowed to continue their subscription:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'archived'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"account-deletion"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#account-deletion"}},[t._v("#")]),t._v(" Account Deletion")]),t._v(" "),n("p",[t._v("If your application allows users to completely delete their account data, you should ensure that you cancel any subscription plans that the user has subscribed to before you delete their data. Otherwise, the user may continue to be billed even after you have deleted their data. You may cancel their subscription using "),n("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel Cashier's"),n("OutboundLink")],1),t._v(" typical subscription management methods. Depending on the billable types used by your application, you may need to adjust this code to your application's unique needs:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("optional")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("recurring")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("cancelNow")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{347:function(t,a,s){t.exports=s.p+"assets/img/incentive.f515e51f.png"},414:function(t,a,s){"use strict";s.r(a);var n=s(55),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,n=t._self._c||a;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#plans"}},[t._v("#")]),t._v(" Plans")]),t._v(" "),n("p"),n("div",{staticClass:"table-of-contents"},[n("ul",[n("li",[n("a",{attrs:{href:"#defining-payment-plans"}},[t._v("Defining Payment Plans")])]),n("li",[n("a",{attrs:{href:"#trial-periods"}},[t._v("Trial Periods")])]),n("li",[n("a",{attrs:{href:"#determining-plan-eligibility"}},[t._v("Determining Plan Eligibility")])]),n("li",[n("a",{attrs:{href:"#per-seat-billing-plans"}},[t._v("Per-Seat Billing Plans")]),n("ul",[n("li",[n("a",{attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("Incrementing / Decrementing The Seat Count")])])])]),n("li",[n("a",{attrs:{href:"#determining-subscription-status"}},[t._v("Determining Subscription Status")])]),n("li",[n("a",{attrs:{href:"#defining-plan-incentive-text"}},[t._v("Defining Plan Incentive Text")])]),n("li",[n("a",{attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("Access A Billable's Spark Plan")])]),n("li",[n("a",{attrs:{href:"#archiving-plans"}},[t._v("Archiving Plans")])]),n("li",[n("a",{attrs:{href:"#account-deletion"}},[t._v("Account Deletion")])])])]),n("p"),t._v(" "),n("h2",{attrs:{id:"defining-payment-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-payment-plans"}},[t._v("#")]),t._v(" Defining Payment Plans")]),t._v(" "),n("p",[n("strong",[t._v("For more information on defining payment plans for your application, please consult the "),n("RouterLink",{attrs:{to:"/1.x/spark-paddle/configuration.html#defining-subscription-plans"}},[t._v("plan configuration documentation")]),t._v(".")],1)]),t._v(" "),n("h2",{attrs:{id:"trial-periods"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#trial-periods"}},[t._v("#")]),t._v(" Trial Periods")]),t._v(" "),n("p",[t._v("By default, the plan configuration in your application's "),n("code",[t._v("config/spark.php")]),t._v(" configuration file contains a "),n("code",[t._v("trial_days")]),t._v(" option with a value of "),n("code",[t._v("5")]),t._v(". This configuration option determines the amount of time the user is allowed to use your application during their free trial period. You are free to modify this configuration value based on your application's needs.")]),t._v(" "),n("p",[t._v("In practical terms, this configuration option simply determines when the "),n("code",[t._v("onTrial")]),t._v(" method of the billable model will begin returning "),n("code",[t._v("false")]),t._v(" instead of "),n("code",[t._v("true")]),t._v(":")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Auth")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("onTrial")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user is still within their trial period...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("div",{staticClass:"custom-block danger"},[n("p",{staticClass:"custom-block-title"},[t._v("Paddle Trials")]),t._v(" "),n("p",[t._v("Because Paddle does not allow plan quantity changes during trial periods, the Paddle edition of Spark does not support requiring a credit card up front when beginning a trial. All trial periods are started without a credit card or payment method provided up front during the user's initial registration process.")]),t._v(" "),n("p",[n("strong",[t._v("Therefore, you may assign each subscription plan zero trial days when configuring subscription plans in your Paddle dashboard.")])])]),t._v(" "),n("h2",{attrs:{id:"determining-plan-eligibility"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-plan-eligibility"}},[t._v("#")]),t._v(" Determining Plan Eligibility")]),t._v(" "),n("p",[t._v("Sometimes, you may wish to place limitations on a particular billing plan. For example, a project management application might limit users on a particular billing plan to a maximum of 10 projects, while a higher priced plan might allow the creation of up to 20 projects.")]),t._v(" "),n("p",[t._v("If you choose to take this approach to billing, you will need to instruct Spark how to determine if a given billable model is eligible to be placed on a particular billing plan. You may accomplish this by modifying the "),n("code",[t._v("checkPlanEligibility")]),t._v(" callback registered within your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class. This callback will be invoked when a billable model attempts to subscribe to or switch to a new subscription plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Validation"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkPlanEligibility")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Plan")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("name")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Basic'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("throw")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("withMessages")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plan'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'You have too many projects for the selected plan.'")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"per-seat-billing-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#per-seat-billing-plans"}},[t._v("#")]),t._v(" Per-Seat Billing Plans")]),t._v(" "),n("p",[t._v('Some applications charge users per "seat" instead of a fixed monthly price. For example, a project management application might charge $10 monthly '),n("strong",[t._v("per project")]),t._v(" such that if a user managed five projects they would be billed $50 monthly.")]),t._v(" "),n("p",[t._v("If your application will be using per-seat billing, you will likely define a single, monthly plan in your application's "),n("code",[t._v("config/spark.php")]),t._v(' configuration file. In addition, you will need to instruct Spark how to calculate the current number of "seats" a billable model is currently using.')]),t._v(" "),n("div",{staticClass:"custom-block danger"},[n("p",{staticClass:"custom-block-title"},[t._v("Enabling Plan Quantity")]),t._v(" "),n("p",[t._v('While creating your subscription plans in Paddle\'s dashboard, make sure you select "Enable quantity". Otherwise, Paddle will ignore any quantity sent by Spark for per-seat billing.')])]),t._v(" "),n("p",[t._v('You may instruct Spark how to calculate the current number of "seats" a billable model is currently using via the '),n("code",[t._v("chargePerSeat")]),t._v(" method when configuring a billable model. Typically, this method should be called within the "),n("code",[t._v("boot")]),t._v(" method of your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("chargePerSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'project'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[t._v("The first argument accepted by the "),n("code",[t._v("chargePerSeat")]),t._v(' method is the term that your application uses to refer to a "seat". In the case of a project management application, this would be a "project". The second argument given to the '),n("code",[t._v("chargePerSeat")]),t._v(' method should be a closure that accepts the billable model and returns the current number of "seats" occupied by that model.')]),t._v(" "),n("p",[t._v("After configuring per-seat billing, Spark will automatically update the wording within your application's billing portal to inform users that billing is calculated on a per-seat basis.")]),t._v(" "),n("h3",{attrs:{id:"incrementing-decrementing-the-seat-count"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("#")]),t._v(" Incrementing / Decrementing The Seat Count")]),t._v(" "),n("p",[t._v("The "),n("code",[t._v("chargePerSeat")]),t._v(" callback that was explained above will inform Spark of the current seat count that should be used when a customer initiates a subscription. However, you still need to inform Spark when to add or remove a seat when a user is using your application. For example, if building a project management application that bills per project, you would need to inform Spark when a user creates or deletes a project. You can accomplish this by calling the "),n("code",[t._v("addSeat")]),t._v(" and "),n("code",[t._v("removeSeat")]),t._v(" method:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("addSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("removeSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"determining-subscription-status"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-subscription-status"}},[t._v("#")]),t._v(" Determining Subscription Status")]),t._v(" "),n("p",[t._v("While building your application, you will often need to inspect a user's subscription status and plan to determine if they are allowed to perform a given action. For example, you may not want to let a user create a project if they are subscribed to a billing plan that only allows a specific number of projects to be created. First, you should review the "),n("RouterLink",{attrs:{to:"/1.x/spark-paddle/middleware.html"}},[t._v("subscription verification middleware")]),t._v(" provided by Spark.")],1),t._v(" "),n("p",[t._v("Additionally, you may always manually inspect a billable model's subscription status using the "),n("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),n("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user has an active subscription...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribedToPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user has a subscription to a plan with a Paddle plan ID of 1000...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"defining-plan-incentive-text"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-plan-incentive-text"}},[t._v("#")]),t._v(" Defining Plan Incentive Text")]),t._v(" "),n("p",[t._v('Spark allows you to define plan "incentive" text to display to your users. For example, you may wish to display the amount saved by choosing to use a yearly plan vs. a monthly plan. Incentive text is shown in the top right corner of the plan\'s card:')]),t._v(" "),n("p",[n("img",{attrs:{src:s(347),alt:"Incentive text example"}})]),t._v(" "),n("p",[t._v("To define incentive text, you may add "),n("code",[t._v("monthly_incentive")]),t._v(" and / or "),n("code",[t._v("yearly_incentive")]),t._v(" configuration options to your plan definition:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_MONTHLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_YEARLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1001")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_incentive'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Save 10%'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 1'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 2'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 3'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"access-a-billable-s-spark-plan"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("#")]),t._v(" Access A Billable's Spark Plan")]),t._v(" "),n("p",[t._v("Sometimes you may wish to access the Spark plan instance for a given billable in order to determine what options are available to the plan. For example, if your plan definition contains the following:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_MONTHLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_YEARLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1001")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'options'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("p",[t._v("You may access the plan and options like so:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$canCreateBackups")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("options")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("??")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("false")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"archiving-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#archiving-plans"}},[t._v("#")]),t._v(" Archiving Plans")]),t._v(" "),n("p",[t._v('If you plan to "archive" or retire a particular plan for your application, you should add the '),n("code",[t._v("archived")]),t._v(" configuration option to the plan's configuration array. You should not completely remove the plan's configuration if existing users of your application that have already subscribed to the plan will be allowed to continue their subscription:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'archived'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"account-deletion"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#account-deletion"}},[t._v("#")]),t._v(" Account Deletion")]),t._v(" "),n("p",[t._v("If your application allows users to completely delete their account data, you should ensure that you cancel any subscription plans that the user has subscribed to before you delete their data. Otherwise, the user may continue to be billed even after you have deleted their data. You may cancel their subscription using "),n("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel Cashier's"),n("OutboundLink")],1),t._v(" typical subscription management methods. Depending on the billable types used by your application, you may need to adjust this code to your application's unique needs:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("optional")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("recurring")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("cancelNow")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/7.ba3c63d4.js b/.vuepress/dist/assets/js/7.f0182c65.js similarity index 99% rename from .vuepress/dist/assets/js/7.ba3c63d4.js rename to .vuepress/dist/assets/js/7.f0182c65.js index 86bfeb7..0eaaa5b 100644 --- a/.vuepress/dist/assets/js/7.ba3c63d4.js +++ b/.vuepress/dist/assets/js/7.f0182c65.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{347:function(t,a,s){t.exports=s.p+"assets/img/incentive.f515e51f.png"},422:function(t,a,s){"use strict";s.r(a);var n=s(55),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,n=t._self._c||a;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#plans"}},[t._v("#")]),t._v(" Plans")]),t._v(" "),n("p"),n("div",{staticClass:"table-of-contents"},[n("ul",[n("li",[n("a",{attrs:{href:"#defining-payment-plans"}},[t._v("Defining Payment Plans")])]),n("li",[n("a",{attrs:{href:"#trial-periods"}},[t._v("Trial Periods")]),n("ul",[n("li",[n("a",{attrs:{href:"#requiring-a-payment-method-up-front"}},[t._v("Requiring A Payment Method Up Front")])])])]),n("li",[n("a",{attrs:{href:"#determining-plan-eligibility"}},[t._v("Determining Plan Eligibility")])]),n("li",[n("a",{attrs:{href:"#per-seat-billing-plans"}},[t._v("Per-Seat Billing Plans")]),n("ul",[n("li",[n("a",{attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("Incrementing / Decrementing The Seat Count")])])])]),n("li",[n("a",{attrs:{href:"#determining-subscription-status"}},[t._v("Determining Subscription Status")])]),n("li",[n("a",{attrs:{href:"#defining-plan-incentive-text"}},[t._v("Defining Plan Incentive Text")])]),n("li",[n("a",{attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("Access A Billable's Spark Plan")])]),n("li",[n("a",{attrs:{href:"#archiving-plans"}},[t._v("Archiving Plans")])]),n("li",[n("a",{attrs:{href:"#account-deletion"}},[t._v("Account Deletion")])])])]),n("p"),t._v(" "),n("h2",{attrs:{id:"defining-payment-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-payment-plans"}},[t._v("#")]),t._v(" Defining Payment Plans")]),t._v(" "),n("p",[n("strong",[t._v("For more information on defining payment plans for your application, please consult the "),n("RouterLink",{attrs:{to:"/1.x/spark-stripe/configuration.html#defining-subscription-plans"}},[t._v("plan configuration documentation")]),t._v(".")],1)]),t._v(" "),n("h2",{attrs:{id:"trial-periods"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#trial-periods"}},[t._v("#")]),t._v(" Trial Periods")]),t._v(" "),n("p",[t._v("By default, the plan configuration in your application's "),n("code",[t._v("config/spark.php")]),t._v(" configuration file contains a "),n("code",[t._v("trial_days")]),t._v(" option with a value of "),n("code",[t._v("5")]),t._v(". This configuration option determines the amount of time the user is allowed to use your application during their free trial period. You are free to modify this configuration value based on your application's needs.")]),t._v(" "),n("p",[t._v("In practical terms, this configuration option simply determines when the "),n("code",[t._v("onTrial")]),t._v(" method of the billable model will begin returning "),n("code",[t._v("false")]),t._v(" instead of "),n("code",[t._v("true")]),t._v(":")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Auth")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("onTrial")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user is still within their trial period...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h3",{attrs:{id:"requiring-a-payment-method-up-front"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#requiring-a-payment-method-up-front"}},[t._v("#")]),t._v(" Requiring A Payment Method Up Front")]),t._v(" "),n("p",[t._v("Some applications may need to require a payment method up front before beginning a free trial. The Stripe edition of Spark supports this behavior. To get started, you will add a "),n("code",[t._v("trial_days")]),t._v(" configuration option to the individual plan configuration array and remove the "),n("code",[t._v("trial_days")]),t._v(" configuration option that is within the billable configuration array:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'user'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'model'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 'trial_days' => 5, Remove this configuration option...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_days'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("p",[t._v("Now, after a billable model's initial registration, the "),n("code",[t._v("trialDays")]),t._v(" method provided by the model instance will return "),n("code",[t._v("false")]),t._v(". You may examine the results of the "),n("code",[t._v("subscribed")]),t._v(" method to conditionally show an alert to your user that they should select a subscription plan before beginning to use your application. For example, if you are using the Blade templating language:")]),t._v(" "),n("div",{staticClass:"language-html extra-class"},[n("pre",{pre:!0,attrs:{class:"language-html"}},[n("code",[t._v("@if (! Auth::user()->subscribed())\n "),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("div")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n You must "),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("a")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("href")]),n("span",{pre:!0,attrs:{class:"token attr-value"}},[n("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("/billing"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("select a subscription plan"),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v(" before continuing.\n "),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n@endif\n")])])]),n("h2",{attrs:{id:"determining-plan-eligibility"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-plan-eligibility"}},[t._v("#")]),t._v(" Determining Plan Eligibility")]),t._v(" "),n("p",[t._v("Sometimes, you may wish to place limitations on a particular billing plan. For example, a project management application might limit users on a particular billing plan to a maximum of 10 projects, while a higher priced plan might allow the creation of up to 20 projects.")]),t._v(" "),n("p",[t._v("If you choose to take this approach to billing, you will need to instruct Spark how to determine if a given billable model is eligible to be placed on a particular billing plan. You may accomplish this by modifying the "),n("code",[t._v("checkPlanEligibility")]),t._v(" callback registered within your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class. This callback will be invoked when a billable model attempts to subscribe to or switch to a new subscription plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Validation"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkPlanEligibility")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Plan")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("name")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Basic'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("throw")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("withMessages")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plan'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'You have too many projects for the selected plan.'")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"per-seat-billing-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#per-seat-billing-plans"}},[t._v("#")]),t._v(" Per-Seat Billing Plans")]),t._v(" "),n("p",[t._v('Some applications charge users per "seat" instead of a fixed monthly price. For example, a project management application might charge $10 monthly '),n("strong",[t._v("per project")]),t._v(" such that if a user managed five projects they would be billed $50 monthly.")]),t._v(" "),n("p",[t._v("If your application will be using per-seat billing, you will likely define a single, monthly plan in your application's "),n("code",[t._v("config/spark.php")]),t._v(' configuration file. In addition, you will need to instruct Spark how to calculate the current number of "seats" a billable model is currently using.')]),t._v(" "),n("p",[t._v('You may instruct Spark how to calculate the current number of "seats" a billable model is currently using via the '),n("code",[t._v("chargePerSeat")]),t._v(" method when configuring a billable model. Typically, this method should be called within the "),n("code",[t._v("boot")]),t._v(" method of your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("chargePerSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'project'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[t._v("The first argument accepted by the "),n("code",[t._v("chargePerSeat")]),t._v(' method is the term that your application uses to refer to a "seat". In the case of a project management application, this would be a "project". The second argument given to the '),n("code",[t._v("chargePerSeat")]),t._v(' method should be a closure that accepts the billable model and returns the current number of "seats" occupied by that model.')]),t._v(" "),n("p",[t._v("After configuring per-seat billing, Spark will automatically update the wording within your application's billing portal to inform users that billing is calculated on a per-seat basis.")]),t._v(" "),n("h3",{attrs:{id:"incrementing-decrementing-the-seat-count"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("#")]),t._v(" Incrementing / Decrementing The Seat Count")]),t._v(" "),n("p",[t._v("The "),n("code",[t._v("chargePerSeat")]),t._v(" callback that was explained above will inform Spark of the current seat count that should be used when a customer initiates a subscription. However, you still need to inform Spark when to add or remove a seat when a user is using your application. For example, if building a project management application that bills per project, you would need to inform Spark when a user creates or deletes a project. You can accomplish this by calling the "),n("code",[t._v("addSeat")]),t._v(" and "),n("code",[t._v("removeSeat")]),t._v(" method:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("addSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("removeSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"determining-subscription-status"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-subscription-status"}},[t._v("#")]),t._v(" Determining Subscription Status")]),t._v(" "),n("p",[t._v("While building your application, you will often need to inspect a user's subscription status and plan to determine if they are allowed to perform a given action. For example, you may not want to let a user create a project if they are subscribed to a billing plan that only allows a specific number of projects to be created. First, you should review the "),n("RouterLink",{attrs:{to:"/1.x/spark-stripe/middleware.html"}},[t._v("subscription verification middleware")]),t._v(" provided by Spark.")],1),t._v(" "),n("p",[t._v("Additionally, you may always manually inspect a billable model's subscription status using the "),n("a",{attrs:{href:"https://laravel.com/docs/billing#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),n("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user has an active subscription...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribedToPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// The user has a subscription to a plan with a Stripe plan / price ID of "price_id"...')]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"defining-plan-incentive-text"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-plan-incentive-text"}},[t._v("#")]),t._v(" Defining Plan Incentive Text")]),t._v(" "),n("p",[t._v('Spark allows you to define plan "incentive" text to display to your users. For example, you may wish to display the amount saved by choosing to use a yearly plan vs. a monthly plan. Incentive text is shown in the top right corner of the plan\'s card:')]),t._v(" "),n("p",[n("img",{attrs:{src:s(347),alt:"Incentive text example"}})]),t._v(" "),n("p",[t._v("To define incentive text, you may add "),n("code",[t._v("monthly_incentive")]),t._v(" and / or "),n("code",[t._v("yearly_incentive")]),t._v(" configuration options to your plan definition:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_incentive'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Save 10%'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 1'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 2'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 3'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"access-a-billable-s-spark-plan"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("#")]),t._v(" Access A Billable's Spark Plan")]),t._v(" "),n("p",[t._v("Sometimes you may wish to access the Spark plan instance for a given billable in order to determine what options are available to the plan. For example, if your plan definition contains the following:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'options'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("p",[t._v("You may access the plan and options like so:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$canCreateBackups")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("options")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("??")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("false")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"archiving-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#archiving-plans"}},[t._v("#")]),t._v(" Archiving Plans")]),t._v(" "),n("p",[t._v('If you plan to "archive" or retire a particular plan for your application, you should add the '),n("code",[t._v("archived")]),t._v(" configuration option to the plan's configuration array. You should not completely remove the plan's configuration if existing users of your application that have already subscribed to the plan will be allowed to continue their subscription:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'archived'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"account-deletion"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#account-deletion"}},[t._v("#")]),t._v(" Account Deletion")]),t._v(" "),n("p",[t._v("If your application allows users to completely delete their account data, you should ensure that you cancel any subscription plans that the user has subscribed to before you delete their data. Otherwise, the user may continue to be billed even after you have deleted their data. You may cancel their subscription using "),n("a",{attrs:{href:"https://laravel.com/docs/billing",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel Cashier's"),n("OutboundLink")],1),t._v(" typical subscription management methods. Depending on the billable types used by your application, you may need to adjust this code to your application's unique needs:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("optional")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("recurring")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("cancelNow")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{347:function(t,a,s){t.exports=s.p+"assets/img/incentive.f515e51f.png"},421:function(t,a,s){"use strict";s.r(a);var n=s(55),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,n=t._self._c||a;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#plans"}},[t._v("#")]),t._v(" Plans")]),t._v(" "),n("p"),n("div",{staticClass:"table-of-contents"},[n("ul",[n("li",[n("a",{attrs:{href:"#defining-payment-plans"}},[t._v("Defining Payment Plans")])]),n("li",[n("a",{attrs:{href:"#trial-periods"}},[t._v("Trial Periods")]),n("ul",[n("li",[n("a",{attrs:{href:"#requiring-a-payment-method-up-front"}},[t._v("Requiring A Payment Method Up Front")])])])]),n("li",[n("a",{attrs:{href:"#determining-plan-eligibility"}},[t._v("Determining Plan Eligibility")])]),n("li",[n("a",{attrs:{href:"#per-seat-billing-plans"}},[t._v("Per-Seat Billing Plans")]),n("ul",[n("li",[n("a",{attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("Incrementing / Decrementing The Seat Count")])])])]),n("li",[n("a",{attrs:{href:"#determining-subscription-status"}},[t._v("Determining Subscription Status")])]),n("li",[n("a",{attrs:{href:"#defining-plan-incentive-text"}},[t._v("Defining Plan Incentive Text")])]),n("li",[n("a",{attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("Access A Billable's Spark Plan")])]),n("li",[n("a",{attrs:{href:"#archiving-plans"}},[t._v("Archiving Plans")])]),n("li",[n("a",{attrs:{href:"#account-deletion"}},[t._v("Account Deletion")])])])]),n("p"),t._v(" "),n("h2",{attrs:{id:"defining-payment-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-payment-plans"}},[t._v("#")]),t._v(" Defining Payment Plans")]),t._v(" "),n("p",[n("strong",[t._v("For more information on defining payment plans for your application, please consult the "),n("RouterLink",{attrs:{to:"/1.x/spark-stripe/configuration.html#defining-subscription-plans"}},[t._v("plan configuration documentation")]),t._v(".")],1)]),t._v(" "),n("h2",{attrs:{id:"trial-periods"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#trial-periods"}},[t._v("#")]),t._v(" Trial Periods")]),t._v(" "),n("p",[t._v("By default, the plan configuration in your application's "),n("code",[t._v("config/spark.php")]),t._v(" configuration file contains a "),n("code",[t._v("trial_days")]),t._v(" option with a value of "),n("code",[t._v("5")]),t._v(". This configuration option determines the amount of time the user is allowed to use your application during their free trial period. You are free to modify this configuration value based on your application's needs.")]),t._v(" "),n("p",[t._v("In practical terms, this configuration option simply determines when the "),n("code",[t._v("onTrial")]),t._v(" method of the billable model will begin returning "),n("code",[t._v("false")]),t._v(" instead of "),n("code",[t._v("true")]),t._v(":")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Auth")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("onTrial")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user is still within their trial period...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h3",{attrs:{id:"requiring-a-payment-method-up-front"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#requiring-a-payment-method-up-front"}},[t._v("#")]),t._v(" Requiring A Payment Method Up Front")]),t._v(" "),n("p",[t._v("Some applications may need to require a payment method up front before beginning a free trial. The Stripe edition of Spark supports this behavior. To get started, you will add a "),n("code",[t._v("trial_days")]),t._v(" configuration option to the individual plan configuration array and remove the "),n("code",[t._v("trial_days")]),t._v(" configuration option that is within the billable configuration array:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'user'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'model'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 'trial_days' => 5, Remove this configuration option...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_days'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("p",[t._v("Now, after a billable model's initial registration, the "),n("code",[t._v("trialDays")]),t._v(" method provided by the model instance will return "),n("code",[t._v("false")]),t._v(". You may examine the results of the "),n("code",[t._v("subscribed")]),t._v(" method to conditionally show an alert to your user that they should select a subscription plan before beginning to use your application. For example, if you are using the Blade templating language:")]),t._v(" "),n("div",{staticClass:"language-html extra-class"},[n("pre",{pre:!0,attrs:{class:"language-html"}},[n("code",[t._v("@if (! Auth::user()->subscribed())\n "),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("div")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n You must "),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("a")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("href")]),n("span",{pre:!0,attrs:{class:"token attr-value"}},[n("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("/billing"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("select a subscription plan"),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v(" before continuing.\n "),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n@endif\n")])])]),n("h2",{attrs:{id:"determining-plan-eligibility"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-plan-eligibility"}},[t._v("#")]),t._v(" Determining Plan Eligibility")]),t._v(" "),n("p",[t._v("Sometimes, you may wish to place limitations on a particular billing plan. For example, a project management application might limit users on a particular billing plan to a maximum of 10 projects, while a higher priced plan might allow the creation of up to 20 projects.")]),t._v(" "),n("p",[t._v("If you choose to take this approach to billing, you will need to instruct Spark how to determine if a given billable model is eligible to be placed on a particular billing plan. You may accomplish this by modifying the "),n("code",[t._v("checkPlanEligibility")]),t._v(" callback registered within your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class. This callback will be invoked when a billable model attempts to subscribe to or switch to a new subscription plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Validation"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkPlanEligibility")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Plan")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("name")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Basic'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("throw")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("withMessages")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plan'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'You have too many projects for the selected plan.'")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"per-seat-billing-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#per-seat-billing-plans"}},[t._v("#")]),t._v(" Per-Seat Billing Plans")]),t._v(" "),n("p",[t._v('Some applications charge users per "seat" instead of a fixed monthly price. For example, a project management application might charge $10 monthly '),n("strong",[t._v("per project")]),t._v(" such that if a user managed five projects they would be billed $50 monthly.")]),t._v(" "),n("p",[t._v("If your application will be using per-seat billing, you will likely define a single, monthly plan in your application's "),n("code",[t._v("config/spark.php")]),t._v(' configuration file. In addition, you will need to instruct Spark how to calculate the current number of "seats" a billable model is currently using.')]),t._v(" "),n("p",[t._v('You may instruct Spark how to calculate the current number of "seats" a billable model is currently using via the '),n("code",[t._v("chargePerSeat")]),t._v(" method when configuring a billable model. Typically, this method should be called within the "),n("code",[t._v("boot")]),t._v(" method of your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("chargePerSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'project'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[t._v("The first argument accepted by the "),n("code",[t._v("chargePerSeat")]),t._v(' method is the term that your application uses to refer to a "seat". In the case of a project management application, this would be a "project". The second argument given to the '),n("code",[t._v("chargePerSeat")]),t._v(' method should be a closure that accepts the billable model and returns the current number of "seats" occupied by that model.')]),t._v(" "),n("p",[t._v("After configuring per-seat billing, Spark will automatically update the wording within your application's billing portal to inform users that billing is calculated on a per-seat basis.")]),t._v(" "),n("h3",{attrs:{id:"incrementing-decrementing-the-seat-count"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("#")]),t._v(" Incrementing / Decrementing The Seat Count")]),t._v(" "),n("p",[t._v("The "),n("code",[t._v("chargePerSeat")]),t._v(" callback that was explained above will inform Spark of the current seat count that should be used when a customer initiates a subscription. However, you still need to inform Spark when to add or remove a seat when a user is using your application. For example, if building a project management application that bills per project, you would need to inform Spark when a user creates or deletes a project. You can accomplish this by calling the "),n("code",[t._v("addSeat")]),t._v(" and "),n("code",[t._v("removeSeat")]),t._v(" method:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("addSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("removeSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"determining-subscription-status"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-subscription-status"}},[t._v("#")]),t._v(" Determining Subscription Status")]),t._v(" "),n("p",[t._v("While building your application, you will often need to inspect a user's subscription status and plan to determine if they are allowed to perform a given action. For example, you may not want to let a user create a project if they are subscribed to a billing plan that only allows a specific number of projects to be created. First, you should review the "),n("RouterLink",{attrs:{to:"/1.x/spark-stripe/middleware.html"}},[t._v("subscription verification middleware")]),t._v(" provided by Spark.")],1),t._v(" "),n("p",[t._v("Additionally, you may always manually inspect a billable model's subscription status using the "),n("a",{attrs:{href:"https://laravel.com/docs/billing#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),n("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user has an active subscription...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribedToPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// The user has a subscription to a plan with a Stripe plan / price ID of "price_id"...')]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"defining-plan-incentive-text"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-plan-incentive-text"}},[t._v("#")]),t._v(" Defining Plan Incentive Text")]),t._v(" "),n("p",[t._v('Spark allows you to define plan "incentive" text to display to your users. For example, you may wish to display the amount saved by choosing to use a yearly plan vs. a monthly plan. Incentive text is shown in the top right corner of the plan\'s card:')]),t._v(" "),n("p",[n("img",{attrs:{src:s(347),alt:"Incentive text example"}})]),t._v(" "),n("p",[t._v("To define incentive text, you may add "),n("code",[t._v("monthly_incentive")]),t._v(" and / or "),n("code",[t._v("yearly_incentive")]),t._v(" configuration options to your plan definition:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_incentive'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Save 10%'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 1'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 2'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 3'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"access-a-billable-s-spark-plan"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("#")]),t._v(" Access A Billable's Spark Plan")]),t._v(" "),n("p",[t._v("Sometimes you may wish to access the Spark plan instance for a given billable in order to determine what options are available to the plan. For example, if your plan definition contains the following:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'options'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("p",[t._v("You may access the plan and options like so:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$canCreateBackups")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("options")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("??")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("false")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"archiving-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#archiving-plans"}},[t._v("#")]),t._v(" Archiving Plans")]),t._v(" "),n("p",[t._v('If you plan to "archive" or retire a particular plan for your application, you should add the '),n("code",[t._v("archived")]),t._v(" configuration option to the plan's configuration array. You should not completely remove the plan's configuration if existing users of your application that have already subscribed to the plan will be allowed to continue their subscription:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'archived'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"account-deletion"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#account-deletion"}},[t._v("#")]),t._v(" Account Deletion")]),t._v(" "),n("p",[t._v("If your application allows users to completely delete their account data, you should ensure that you cancel any subscription plans that the user has subscribed to before you delete their data. Otherwise, the user may continue to be billed even after you have deleted their data. You may cancel their subscription using "),n("a",{attrs:{href:"https://laravel.com/docs/billing",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel Cashier's"),n("OutboundLink")],1),t._v(" typical subscription management methods. Depending on the billable types used by your application, you may need to adjust this code to your application's unique needs:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("optional")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("recurring")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("cancelNow")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/8.9c7fdb39.js b/.vuepress/dist/assets/js/8.c63c2f3a.js similarity index 99% rename from .vuepress/dist/assets/js/8.9c7fdb39.js rename to .vuepress/dist/assets/js/8.c63c2f3a.js index a006e4e..fc6b1aa 100644 --- a/.vuepress/dist/assets/js/8.9c7fdb39.js +++ b/.vuepress/dist/assets/js/8.c63c2f3a.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{347:function(t,a,s){t.exports=s.p+"assets/img/incentive.f515e51f.png"},434:function(t,a,s){"use strict";s.r(a);var n=s(55),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,n=t._self._c||a;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#plans"}},[t._v("#")]),t._v(" Plans")]),t._v(" "),n("p"),n("div",{staticClass:"table-of-contents"},[n("ul",[n("li",[n("a",{attrs:{href:"#defining-payment-plans"}},[t._v("Defining Payment Plans")])]),n("li",[n("a",{attrs:{href:"#trial-periods"}},[t._v("Trial Periods")])]),n("li",[n("a",{attrs:{href:"#determining-plan-eligibility"}},[t._v("Determining Plan Eligibility")])]),n("li",[n("a",{attrs:{href:"#per-seat-billing-plans"}},[t._v("Per-Seat Billing Plans")]),n("ul",[n("li",[n("a",{attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("Incrementing / Decrementing The Seat Count")])])])]),n("li",[n("a",{attrs:{href:"#determining-subscription-status"}},[t._v("Determining Subscription Status")])]),n("li",[n("a",{attrs:{href:"#defining-plan-incentive-text"}},[t._v("Defining Plan Incentive Text")])]),n("li",[n("a",{attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("Access A Billable's Spark Plan")])]),n("li",[n("a",{attrs:{href:"#archiving-plans"}},[t._v("Archiving Plans")])]),n("li",[n("a",{attrs:{href:"#account-deletion"}},[t._v("Account Deletion")])])])]),n("p"),t._v(" "),n("h2",{attrs:{id:"defining-payment-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-payment-plans"}},[t._v("#")]),t._v(" Defining Payment Plans")]),t._v(" "),n("p",[n("strong",[t._v("For more information on defining payment plans for your application, please consult the "),n("RouterLink",{attrs:{to:"/2.x/spark-paddle/configuration.html#defining-subscription-plans"}},[t._v("plan configuration documentation")]),t._v(".")],1)]),t._v(" "),n("h2",{attrs:{id:"trial-periods"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#trial-periods"}},[t._v("#")]),t._v(" Trial Periods")]),t._v(" "),n("p",[t._v("By default, the plan configuration in your application's "),n("code",[t._v("config/spark.php")]),t._v(" configuration file contains a "),n("code",[t._v("trial_days")]),t._v(" option with a value of "),n("code",[t._v("5")]),t._v(". This configuration option determines the amount of time the user is allowed to use your application during their free trial period. You are free to modify this configuration value based on your application's needs.")]),t._v(" "),n("p",[t._v("In practical terms, this configuration option simply determines when the "),n("code",[t._v("onTrial")]),t._v(" method of the billable model will begin returning "),n("code",[t._v("false")]),t._v(" instead of "),n("code",[t._v("true")]),t._v(":")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Auth")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("onTrial")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user is still within their trial period...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("div",{staticClass:"custom-block danger"},[n("p",{staticClass:"custom-block-title"},[t._v("Paddle Trials")]),t._v(" "),n("p",[t._v("Because Paddle does not allow plan quantity changes during trial periods, the Paddle edition of Spark does not support requiring a credit card up front when beginning a trial. All trial periods are started without a credit card or payment method provided up front during the user's initial registration process.")]),t._v(" "),n("p",[n("strong",[t._v("Therefore, you may assign each subscription plan zero trial days when configuring subscription plans in your Paddle dashboard.")])])]),t._v(" "),n("h2",{attrs:{id:"determining-plan-eligibility"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-plan-eligibility"}},[t._v("#")]),t._v(" Determining Plan Eligibility")]),t._v(" "),n("p",[t._v("Sometimes, you may wish to place limitations on a particular billing plan. For example, a project management application might limit users on a particular billing plan to a maximum of 10 projects, while a higher priced plan might allow the creation of up to 20 projects.")]),t._v(" "),n("p",[t._v("If you choose to take this approach to billing, you will need to instruct Spark how to determine if a given billable model is eligible to be placed on a particular billing plan. You may accomplish this by modifying the "),n("code",[t._v("checkPlanEligibility")]),t._v(" callback registered within your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class. This callback will be invoked when a billable model attempts to subscribe to or switch to a new subscription plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Validation"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkPlanEligibility")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Plan")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("name")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Basic'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("throw")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("withMessages")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plan'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'You have too many projects for the selected plan.'")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"per-seat-billing-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#per-seat-billing-plans"}},[t._v("#")]),t._v(" Per-Seat Billing Plans")]),t._v(" "),n("p",[t._v('Some applications charge users per "seat" instead of a fixed monthly price. For example, a project management application might charge $10 monthly '),n("strong",[t._v("per project")]),t._v(" such that if a user managed five projects they would be billed $50 monthly.")]),t._v(" "),n("p",[t._v("If your application will be using per-seat billing, you will likely define a single, monthly plan in your application's "),n("code",[t._v("config/spark.php")]),t._v(' configuration file. In addition, you will need to instruct Spark how to calculate the current number of "seats" a billable model is currently using.')]),t._v(" "),n("div",{staticClass:"custom-block danger"},[n("p",{staticClass:"custom-block-title"},[t._v("Enabling Plan Quantity")]),t._v(" "),n("p",[t._v('While creating your subscription plans in Paddle\'s dashboard, make sure you select "Enable quantity". Otherwise, Paddle will ignore any quantity sent by Spark for per-seat billing.')])]),t._v(" "),n("p",[t._v('You may instruct Spark how to calculate the current number of "seats" a billable model is currently using via the '),n("code",[t._v("chargePerSeat")]),t._v(" method when configuring a billable model. Typically, this method should be called within the "),n("code",[t._v("boot")]),t._v(" method of your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("chargePerSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'project'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[t._v("The first argument accepted by the "),n("code",[t._v("chargePerSeat")]),t._v(' method is the term that your application uses to refer to a "seat". In the case of a project management application, this would be a "project". The second argument given to the '),n("code",[t._v("chargePerSeat")]),t._v(' method should be a closure that accepts the billable model and returns the current number of "seats" occupied by that model.')]),t._v(" "),n("p",[t._v("After configuring per-seat billing, Spark will automatically update the wording within your application's billing portal to inform users that billing is calculated on a per-seat basis.")]),t._v(" "),n("h3",{attrs:{id:"incrementing-decrementing-the-seat-count"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("#")]),t._v(" Incrementing / Decrementing The Seat Count")]),t._v(" "),n("p",[t._v("The "),n("code",[t._v("chargePerSeat")]),t._v(" callback that was explained above will inform Spark of the current seat count that should be used when a customer initiates a subscription. However, you still need to inform Spark when to add or remove a seat when a user is using your application. For example, if building a project management application that bills per project, you would need to inform Spark when a user creates or deletes a project. You can accomplish this by calling the "),n("code",[t._v("addSeat")]),t._v(" and "),n("code",[t._v("removeSeat")]),t._v(" method:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("addSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("removeSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"determining-subscription-status"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-subscription-status"}},[t._v("#")]),t._v(" Determining Subscription Status")]),t._v(" "),n("p",[t._v("While building your application, you will often need to inspect a user's subscription status and plan to determine if they are allowed to perform a given action. For example, you may not want to let a user create a project if they are subscribed to a billing plan that only allows a specific number of projects to be created. First, you should review the "),n("RouterLink",{attrs:{to:"/2.x/spark-paddle/middleware.html"}},[t._v("subscription verification middleware")]),t._v(" provided by Spark.")],1),t._v(" "),n("p",[t._v("Additionally, you may always manually inspect a billable model's subscription status using the "),n("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),n("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user has an active subscription...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribedToPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user has a subscription to a plan with a Paddle plan ID of 1000...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"defining-plan-incentive-text"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-plan-incentive-text"}},[t._v("#")]),t._v(" Defining Plan Incentive Text")]),t._v(" "),n("p",[t._v('Spark allows you to define plan "incentive" text to display to your users. For example, you may wish to display the amount saved by choosing to use a yearly plan vs. a monthly plan. Incentive text is shown in the top right corner of the plan\'s card:')]),t._v(" "),n("p",[n("img",{attrs:{src:s(347),alt:"Incentive text example"}})]),t._v(" "),n("p",[t._v("To define incentive text, you may add "),n("code",[t._v("monthly_incentive")]),t._v(" and / or "),n("code",[t._v("yearly_incentive")]),t._v(" configuration options to your plan definition:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_MONTHLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_YEARLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1001")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_incentive'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Save 10%'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 1'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 2'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 3'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"access-a-billable-s-spark-plan"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("#")]),t._v(" Access A Billable's Spark Plan")]),t._v(" "),n("p",[t._v("Sometimes you may wish to access the Spark plan instance for a given billable in order to determine what options are available to the plan. For example, if your plan definition contains the following:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_MONTHLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_YEARLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1001")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'options'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("p",[t._v("You may access the plan and options like so:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$canCreateBackups")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("options")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("??")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("false")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"archiving-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#archiving-plans"}},[t._v("#")]),t._v(" Archiving Plans")]),t._v(" "),n("p",[t._v('If you plan to "archive" or retire a particular plan for your application, you should add the '),n("code",[t._v("archived")]),t._v(" configuration option to the plan's configuration array. You should not completely remove the plan's configuration if existing users of your application that have already subscribed to the plan will be allowed to continue their subscription:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'archived'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"account-deletion"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#account-deletion"}},[t._v("#")]),t._v(" Account Deletion")]),t._v(" "),n("p",[t._v("If your application allows users to completely delete their account data, you should ensure that you cancel any subscription plans that the user has subscribed to before you delete their data. Otherwise, the user may continue to be billed even after you have deleted their data. You may cancel their subscription using "),n("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel Cashier's"),n("OutboundLink")],1),t._v(" typical subscription management methods. Depending on the billable types used by your application, you may need to adjust this code to your application's unique needs:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("optional")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("recurring")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("cancelNow")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{347:function(t,a,s){t.exports=s.p+"assets/img/incentive.f515e51f.png"},432:function(t,a,s){"use strict";s.r(a);var n=s(55),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,n=t._self._c||a;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#plans"}},[t._v("#")]),t._v(" Plans")]),t._v(" "),n("p"),n("div",{staticClass:"table-of-contents"},[n("ul",[n("li",[n("a",{attrs:{href:"#defining-payment-plans"}},[t._v("Defining Payment Plans")])]),n("li",[n("a",{attrs:{href:"#trial-periods"}},[t._v("Trial Periods")])]),n("li",[n("a",{attrs:{href:"#determining-plan-eligibility"}},[t._v("Determining Plan Eligibility")])]),n("li",[n("a",{attrs:{href:"#per-seat-billing-plans"}},[t._v("Per-Seat Billing Plans")]),n("ul",[n("li",[n("a",{attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("Incrementing / Decrementing The Seat Count")])])])]),n("li",[n("a",{attrs:{href:"#determining-subscription-status"}},[t._v("Determining Subscription Status")])]),n("li",[n("a",{attrs:{href:"#defining-plan-incentive-text"}},[t._v("Defining Plan Incentive Text")])]),n("li",[n("a",{attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("Access A Billable's Spark Plan")])]),n("li",[n("a",{attrs:{href:"#archiving-plans"}},[t._v("Archiving Plans")])]),n("li",[n("a",{attrs:{href:"#account-deletion"}},[t._v("Account Deletion")])])])]),n("p"),t._v(" "),n("h2",{attrs:{id:"defining-payment-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-payment-plans"}},[t._v("#")]),t._v(" Defining Payment Plans")]),t._v(" "),n("p",[n("strong",[t._v("For more information on defining payment plans for your application, please consult the "),n("RouterLink",{attrs:{to:"/2.x/spark-paddle/configuration.html#defining-subscription-plans"}},[t._v("plan configuration documentation")]),t._v(".")],1)]),t._v(" "),n("h2",{attrs:{id:"trial-periods"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#trial-periods"}},[t._v("#")]),t._v(" Trial Periods")]),t._v(" "),n("p",[t._v("By default, the plan configuration in your application's "),n("code",[t._v("config/spark.php")]),t._v(" configuration file contains a "),n("code",[t._v("trial_days")]),t._v(" option with a value of "),n("code",[t._v("5")]),t._v(". This configuration option determines the amount of time the user is allowed to use your application during their free trial period. You are free to modify this configuration value based on your application's needs.")]),t._v(" "),n("p",[t._v("In practical terms, this configuration option simply determines when the "),n("code",[t._v("onTrial")]),t._v(" method of the billable model will begin returning "),n("code",[t._v("false")]),t._v(" instead of "),n("code",[t._v("true")]),t._v(":")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Auth")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("onTrial")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user is still within their trial period...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("div",{staticClass:"custom-block danger"},[n("p",{staticClass:"custom-block-title"},[t._v("Paddle Trials")]),t._v(" "),n("p",[t._v("Because Paddle does not allow plan quantity changes during trial periods, the Paddle edition of Spark does not support requiring a credit card up front when beginning a trial. All trial periods are started without a credit card or payment method provided up front during the user's initial registration process.")]),t._v(" "),n("p",[n("strong",[t._v("Therefore, you may assign each subscription plan zero trial days when configuring subscription plans in your Paddle dashboard.")])])]),t._v(" "),n("h2",{attrs:{id:"determining-plan-eligibility"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-plan-eligibility"}},[t._v("#")]),t._v(" Determining Plan Eligibility")]),t._v(" "),n("p",[t._v("Sometimes, you may wish to place limitations on a particular billing plan. For example, a project management application might limit users on a particular billing plan to a maximum of 10 projects, while a higher priced plan might allow the creation of up to 20 projects.")]),t._v(" "),n("p",[t._v("If you choose to take this approach to billing, you will need to instruct Spark how to determine if a given billable model is eligible to be placed on a particular billing plan. You may accomplish this by modifying the "),n("code",[t._v("checkPlanEligibility")]),t._v(" callback registered within your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class. This callback will be invoked when a billable model attempts to subscribe to or switch to a new subscription plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Validation"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkPlanEligibility")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Plan")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("name")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Basic'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("throw")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("withMessages")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plan'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'You have too many projects for the selected plan.'")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"per-seat-billing-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#per-seat-billing-plans"}},[t._v("#")]),t._v(" Per-Seat Billing Plans")]),t._v(" "),n("p",[t._v('Some applications charge users per "seat" instead of a fixed monthly price. For example, a project management application might charge $10 monthly '),n("strong",[t._v("per project")]),t._v(" such that if a user managed five projects they would be billed $50 monthly.")]),t._v(" "),n("p",[t._v("If your application will be using per-seat billing, you will likely define a single, monthly plan in your application's "),n("code",[t._v("config/spark.php")]),t._v(' configuration file. In addition, you will need to instruct Spark how to calculate the current number of "seats" a billable model is currently using.')]),t._v(" "),n("div",{staticClass:"custom-block danger"},[n("p",{staticClass:"custom-block-title"},[t._v("Enabling Plan Quantity")]),t._v(" "),n("p",[t._v('While creating your subscription plans in Paddle\'s dashboard, make sure you select "Enable quantity". Otherwise, Paddle will ignore any quantity sent by Spark for per-seat billing.')])]),t._v(" "),n("p",[t._v('You may instruct Spark how to calculate the current number of "seats" a billable model is currently using via the '),n("code",[t._v("chargePerSeat")]),t._v(" method when configuring a billable model. Typically, this method should be called within the "),n("code",[t._v("boot")]),t._v(" method of your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("chargePerSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'project'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[t._v("The first argument accepted by the "),n("code",[t._v("chargePerSeat")]),t._v(' method is the term that your application uses to refer to a "seat". In the case of a project management application, this would be a "project". The second argument given to the '),n("code",[t._v("chargePerSeat")]),t._v(' method should be a closure that accepts the billable model and returns the current number of "seats" occupied by that model.')]),t._v(" "),n("p",[t._v("After configuring per-seat billing, Spark will automatically update the wording within your application's billing portal to inform users that billing is calculated on a per-seat basis.")]),t._v(" "),n("h3",{attrs:{id:"incrementing-decrementing-the-seat-count"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("#")]),t._v(" Incrementing / Decrementing The Seat Count")]),t._v(" "),n("p",[t._v("The "),n("code",[t._v("chargePerSeat")]),t._v(" callback that was explained above will inform Spark of the current seat count that should be used when a customer initiates a subscription. However, you still need to inform Spark when to add or remove a seat when a user is using your application. For example, if building a project management application that bills per project, you would need to inform Spark when a user creates or deletes a project. You can accomplish this by calling the "),n("code",[t._v("addSeat")]),t._v(" and "),n("code",[t._v("removeSeat")]),t._v(" method:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("addSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("removeSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"determining-subscription-status"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-subscription-status"}},[t._v("#")]),t._v(" Determining Subscription Status")]),t._v(" "),n("p",[t._v("While building your application, you will often need to inspect a user's subscription status and plan to determine if they are allowed to perform a given action. For example, you may not want to let a user create a project if they are subscribed to a billing plan that only allows a specific number of projects to be created. First, you should review the "),n("RouterLink",{attrs:{to:"/2.x/spark-paddle/middleware.html"}},[t._v("subscription verification middleware")]),t._v(" provided by Spark.")],1),t._v(" "),n("p",[t._v("Additionally, you may always manually inspect a billable model's subscription status using the "),n("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),n("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user has an active subscription...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribedToPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user has a subscription to a plan with a Paddle plan ID of 1000...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"defining-plan-incentive-text"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-plan-incentive-text"}},[t._v("#")]),t._v(" Defining Plan Incentive Text")]),t._v(" "),n("p",[t._v('Spark allows you to define plan "incentive" text to display to your users. For example, you may wish to display the amount saved by choosing to use a yearly plan vs. a monthly plan. Incentive text is shown in the top right corner of the plan\'s card:')]),t._v(" "),n("p",[n("img",{attrs:{src:s(347),alt:"Incentive text example"}})]),t._v(" "),n("p",[t._v("To define incentive text, you may add "),n("code",[t._v("monthly_incentive")]),t._v(" and / or "),n("code",[t._v("yearly_incentive")]),t._v(" configuration options to your plan definition:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_MONTHLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_YEARLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1001")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_incentive'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Save 10%'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 1'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 2'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 3'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"access-a-billable-s-spark-plan"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("#")]),t._v(" Access A Billable's Spark Plan")]),t._v(" "),n("p",[t._v("Sometimes you may wish to access the Spark plan instance for a given billable in order to determine what options are available to the plan. For example, if your plan definition contains the following:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_MONTHLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("env")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'SPARK_STANDARD_YEARLY_PLAN'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1001")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'options'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("p",[t._v("You may access the plan and options like so:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$canCreateBackups")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("options")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("??")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("false")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"archiving-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#archiving-plans"}},[t._v("#")]),t._v(" Archiving Plans")]),t._v(" "),n("p",[t._v('If you plan to "archive" or retire a particular plan for your application, you should add the '),n("code",[t._v("archived")]),t._v(" configuration option to the plan's configuration array. You should not completely remove the plan's configuration if existing users of your application that have already subscribed to the plan will be allowed to continue their subscription:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'archived'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"account-deletion"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#account-deletion"}},[t._v("#")]),t._v(" Account Deletion")]),t._v(" "),n("p",[t._v("If your application allows users to completely delete their account data, you should ensure that you cancel any subscription plans that the user has subscribed to before you delete their data. Otherwise, the user may continue to be billed even after you have deleted their data. You may cancel their subscription using "),n("a",{attrs:{href:"https://laravel.com/docs/cashier-paddle",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel Cashier's"),n("OutboundLink")],1),t._v(" typical subscription management methods. Depending on the billable types used by your application, you may need to adjust this code to your application's unique needs:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("optional")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("recurring")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("cancelNow")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/9.36f96429.js b/.vuepress/dist/assets/js/9.9b279207.js similarity index 99% rename from .vuepress/dist/assets/js/9.36f96429.js rename to .vuepress/dist/assets/js/9.9b279207.js index 7cf44df..4a0724a 100644 --- a/.vuepress/dist/assets/js/9.36f96429.js +++ b/.vuepress/dist/assets/js/9.9b279207.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{347:function(t,a,s){t.exports=s.p+"assets/img/incentive.f515e51f.png"},449:function(t,a,s){"use strict";s.r(a);var n=s(55),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,n=t._self._c||a;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#plans"}},[t._v("#")]),t._v(" Plans")]),t._v(" "),n("p"),n("div",{staticClass:"table-of-contents"},[n("ul",[n("li",[n("a",{attrs:{href:"#defining-payment-plans"}},[t._v("Defining Payment Plans")])]),n("li",[n("a",{attrs:{href:"#trial-periods"}},[t._v("Trial Periods")]),n("ul",[n("li",[n("a",{attrs:{href:"#requiring-a-payment-method-up-front"}},[t._v("Requiring A Payment Method Up Front")])])])]),n("li",[n("a",{attrs:{href:"#determining-plan-eligibility"}},[t._v("Determining Plan Eligibility")])]),n("li",[n("a",{attrs:{href:"#per-seat-billing-plans"}},[t._v("Per-Seat Billing Plans")]),n("ul",[n("li",[n("a",{attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("Incrementing / Decrementing The Seat Count")])])])]),n("li",[n("a",{attrs:{href:"#determining-subscription-status"}},[t._v("Determining Subscription Status")])]),n("li",[n("a",{attrs:{href:"#defining-plan-incentive-text"}},[t._v("Defining Plan Incentive Text")])]),n("li",[n("a",{attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("Access A Billable's Spark Plan")])]),n("li",[n("a",{attrs:{href:"#archiving-plans"}},[t._v("Archiving Plans")])]),n("li",[n("a",{attrs:{href:"#account-deletion"}},[t._v("Account Deletion")])])])]),n("p"),t._v(" "),n("h2",{attrs:{id:"defining-payment-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-payment-plans"}},[t._v("#")]),t._v(" Defining Payment Plans")]),t._v(" "),n("p",[n("strong",[t._v("For more information on defining payment plans for your application, please consult the "),n("RouterLink",{attrs:{to:"/2.x/spark-stripe/configuration.html#defining-subscription-plans"}},[t._v("plan configuration documentation")]),t._v(".")],1)]),t._v(" "),n("h2",{attrs:{id:"trial-periods"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#trial-periods"}},[t._v("#")]),t._v(" Trial Periods")]),t._v(" "),n("p",[t._v("By default, the plan configuration in your application's "),n("code",[t._v("config/spark.php")]),t._v(" configuration file contains a "),n("code",[t._v("trial_days")]),t._v(" option with a value of "),n("code",[t._v("5")]),t._v(". This configuration option determines the amount of time the user is allowed to use your application during their free trial period. You are free to modify this configuration value based on your application's needs.")]),t._v(" "),n("p",[t._v("In practical terms, this configuration option simply determines when the "),n("code",[t._v("onTrial")]),t._v(" method of the billable model will begin returning "),n("code",[t._v("false")]),t._v(" instead of "),n("code",[t._v("true")]),t._v(":")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Auth")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("onTrial")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user is still within their trial period...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h3",{attrs:{id:"requiring-a-payment-method-up-front"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#requiring-a-payment-method-up-front"}},[t._v("#")]),t._v(" Requiring A Payment Method Up Front")]),t._v(" "),n("p",[t._v("Some applications may need to require a payment method up front before beginning a free trial. The Stripe edition of Spark supports this behavior. To get started, you will add a "),n("code",[t._v("trial_days")]),t._v(" configuration option to the individual plan configuration array and remove the "),n("code",[t._v("trial_days")]),t._v(" configuration option that is within the billable configuration array:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'user'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'model'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 'trial_days' => 5, Remove this configuration option...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_days'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("p",[t._v("Now, after a billable model's initial registration, the "),n("code",[t._v("trialDays")]),t._v(" method provided by the model instance will return "),n("code",[t._v("false")]),t._v(". You may examine the results of the "),n("code",[t._v("subscribed")]),t._v(" method to conditionally show an alert to your user that they should select a subscription plan before beginning to use your application. For example, if you are using the Blade templating language:")]),t._v(" "),n("div",{staticClass:"language-html extra-class"},[n("pre",{pre:!0,attrs:{class:"language-html"}},[n("code",[t._v("@if (! Auth::user()->subscribed())\n "),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("div")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n You must "),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("a")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("href")]),n("span",{pre:!0,attrs:{class:"token attr-value"}},[n("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("/billing"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("select a subscription plan"),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v(" before continuing.\n "),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n@endif\n")])])]),n("h2",{attrs:{id:"determining-plan-eligibility"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-plan-eligibility"}},[t._v("#")]),t._v(" Determining Plan Eligibility")]),t._v(" "),n("p",[t._v("Sometimes, you may wish to place limitations on a particular billing plan. For example, a project management application might limit users on a particular billing plan to a maximum of 10 projects, while a higher priced plan might allow the creation of up to 20 projects.")]),t._v(" "),n("p",[t._v("If you choose to take this approach to billing, you will need to instruct Spark how to determine if a given billable model is eligible to be placed on a particular billing plan. You may accomplish this by modifying the "),n("code",[t._v("checkPlanEligibility")]),t._v(" callback registered within your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class. This callback will be invoked when a billable model attempts to subscribe to or switch to a new subscription plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Validation"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkPlanEligibility")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Plan")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("name")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Basic'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("throw")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("withMessages")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plan'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'You have too many projects for the selected plan.'")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"per-seat-billing-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#per-seat-billing-plans"}},[t._v("#")]),t._v(" Per-Seat Billing Plans")]),t._v(" "),n("p",[t._v('Some applications charge users per "seat" instead of a fixed monthly price. For example, a project management application might charge $10 monthly '),n("strong",[t._v("per project")]),t._v(" such that if a user managed five projects they would be billed $50 monthly.")]),t._v(" "),n("p",[t._v("If your application will be using per-seat billing, you will likely define a single, monthly plan in your application's "),n("code",[t._v("config/spark.php")]),t._v(' configuration file. In addition, you will need to instruct Spark how to calculate the current number of "seats" a billable model is currently using.')]),t._v(" "),n("p",[t._v('You may instruct Spark how to calculate the current number of "seats" a billable model is currently using via the '),n("code",[t._v("chargePerSeat")]),t._v(" method when configuring a billable model. Typically, this method should be called within the "),n("code",[t._v("boot")]),t._v(" method of your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("chargePerSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'project'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[t._v("The first argument accepted by the "),n("code",[t._v("chargePerSeat")]),t._v(' method is the term that your application uses to refer to a "seat". In the case of a project management application, this would be a "project". The second argument given to the '),n("code",[t._v("chargePerSeat")]),t._v(' method should be a closure that accepts the billable model and returns the current number of "seats" occupied by that model.')]),t._v(" "),n("p",[t._v("After configuring per-seat billing, Spark will automatically update the wording within your application's billing portal to inform users that billing is calculated on a per-seat basis.")]),t._v(" "),n("h3",{attrs:{id:"incrementing-decrementing-the-seat-count"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("#")]),t._v(" Incrementing / Decrementing The Seat Count")]),t._v(" "),n("p",[t._v("The "),n("code",[t._v("chargePerSeat")]),t._v(" callback that was explained above will inform Spark of the current seat count that should be used when a customer initiates a subscription. However, you still need to inform Spark when to add or remove a seat when a user is using your application. For example, if building a project management application that bills per project, you would need to inform Spark when a user creates or deletes a project. You can accomplish this by calling the "),n("code",[t._v("addSeat")]),t._v(" and "),n("code",[t._v("removeSeat")]),t._v(" method:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("addSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("removeSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"determining-subscription-status"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-subscription-status"}},[t._v("#")]),t._v(" Determining Subscription Status")]),t._v(" "),n("p",[t._v("While building your application, you will often need to inspect a user's subscription status and plan to determine if they are allowed to perform a given action. For example, you may not want to let a user create a project if they are subscribed to a billing plan that only allows a specific number of projects to be created. First, you should review the "),n("RouterLink",{attrs:{to:"/2.x/spark-stripe/middleware.html"}},[t._v("subscription verification middleware")]),t._v(" provided by Spark.")],1),t._v(" "),n("p",[t._v("Additionally, you may always manually inspect a billable model's subscription status using the "),n("a",{attrs:{href:"https://laravel.com/docs/billing#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),n("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user has an active subscription...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribedToPrice")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// The user has a subscription to a plan with a Stripe plan / price ID of "price_id"...')]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"defining-plan-incentive-text"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-plan-incentive-text"}},[t._v("#")]),t._v(" Defining Plan Incentive Text")]),t._v(" "),n("p",[t._v('Spark allows you to define plan "incentive" text to display to your users. For example, you may wish to display the amount saved by choosing to use a yearly plan vs. a monthly plan. Incentive text is shown in the top right corner of the plan\'s card:')]),t._v(" "),n("p",[n("img",{attrs:{src:s(347),alt:"Incentive text example"}})]),t._v(" "),n("p",[t._v("To define incentive text, you may add "),n("code",[t._v("monthly_incentive")]),t._v(" and / or "),n("code",[t._v("yearly_incentive")]),t._v(" configuration options to your plan definition:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_incentive'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Save 10%'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 1'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 2'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 3'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"access-a-billable-s-spark-plan"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("#")]),t._v(" Access A Billable's Spark Plan")]),t._v(" "),n("p",[t._v("Sometimes you may wish to access the Spark plan instance for a given billable in order to determine what options are available to the plan. For example, if your plan definition contains the following:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'options'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("p",[t._v("You may access the plan and options like so:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$canCreateBackups")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("options")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("??")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("false")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"archiving-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#archiving-plans"}},[t._v("#")]),t._v(" Archiving Plans")]),t._v(" "),n("p",[t._v('If you plan to "archive" or retire a particular plan for your application, you should add the '),n("code",[t._v("archived")]),t._v(" configuration option to the plan's configuration array. You should not completely remove the plan's configuration if existing users of your application that have already subscribed to the plan will be allowed to continue their subscription:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'archived'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"account-deletion"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#account-deletion"}},[t._v("#")]),t._v(" Account Deletion")]),t._v(" "),n("p",[t._v("If your application allows users to completely delete their account data, you should ensure that you cancel any subscription plans that the user has subscribed to before you delete their data. Otherwise, the user may continue to be billed even after you have deleted their data. You may cancel their subscription using "),n("a",{attrs:{href:"https://laravel.com/docs/billing",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel Cashier's"),n("OutboundLink")],1),t._v(" typical subscription management methods. Depending on the billable types used by your application, you may need to adjust this code to your application's unique needs:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("optional")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("recurring")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("cancelNow")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{347:function(t,a,s){t.exports=s.p+"assets/img/incentive.f515e51f.png"},441:function(t,a,s){"use strict";s.r(a);var n=s(55),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,n=t._self._c||a;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#plans"}},[t._v("#")]),t._v(" Plans")]),t._v(" "),n("p"),n("div",{staticClass:"table-of-contents"},[n("ul",[n("li",[n("a",{attrs:{href:"#defining-payment-plans"}},[t._v("Defining Payment Plans")])]),n("li",[n("a",{attrs:{href:"#trial-periods"}},[t._v("Trial Periods")]),n("ul",[n("li",[n("a",{attrs:{href:"#requiring-a-payment-method-up-front"}},[t._v("Requiring A Payment Method Up Front")])])])]),n("li",[n("a",{attrs:{href:"#determining-plan-eligibility"}},[t._v("Determining Plan Eligibility")])]),n("li",[n("a",{attrs:{href:"#per-seat-billing-plans"}},[t._v("Per-Seat Billing Plans")]),n("ul",[n("li",[n("a",{attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("Incrementing / Decrementing The Seat Count")])])])]),n("li",[n("a",{attrs:{href:"#determining-subscription-status"}},[t._v("Determining Subscription Status")])]),n("li",[n("a",{attrs:{href:"#defining-plan-incentive-text"}},[t._v("Defining Plan Incentive Text")])]),n("li",[n("a",{attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("Access A Billable's Spark Plan")])]),n("li",[n("a",{attrs:{href:"#archiving-plans"}},[t._v("Archiving Plans")])]),n("li",[n("a",{attrs:{href:"#account-deletion"}},[t._v("Account Deletion")])])])]),n("p"),t._v(" "),n("h2",{attrs:{id:"defining-payment-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-payment-plans"}},[t._v("#")]),t._v(" Defining Payment Plans")]),t._v(" "),n("p",[n("strong",[t._v("For more information on defining payment plans for your application, please consult the "),n("RouterLink",{attrs:{to:"/2.x/spark-stripe/configuration.html#defining-subscription-plans"}},[t._v("plan configuration documentation")]),t._v(".")],1)]),t._v(" "),n("h2",{attrs:{id:"trial-periods"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#trial-periods"}},[t._v("#")]),t._v(" Trial Periods")]),t._v(" "),n("p",[t._v("By default, the plan configuration in your application's "),n("code",[t._v("config/spark.php")]),t._v(" configuration file contains a "),n("code",[t._v("trial_days")]),t._v(" option with a value of "),n("code",[t._v("5")]),t._v(". This configuration option determines the amount of time the user is allowed to use your application during their free trial period. You are free to modify this configuration value based on your application's needs.")]),t._v(" "),n("p",[t._v("In practical terms, this configuration option simply determines when the "),n("code",[t._v("onTrial")]),t._v(" method of the billable model will begin returning "),n("code",[t._v("false")]),t._v(" instead of "),n("code",[t._v("true")]),t._v(":")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Auth")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("user")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("onTrial")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user is still within their trial period...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h3",{attrs:{id:"requiring-a-payment-method-up-front"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#requiring-a-payment-method-up-front"}},[t._v("#")]),t._v(" Requiring A Payment Method Up Front")]),t._v(" "),n("p",[t._v("Some applications may need to require a payment method up front before beginning a free trial. The Stripe edition of Spark supports this behavior. To get started, you will add a "),n("code",[t._v("trial_days")]),t._v(" configuration option to the individual plan configuration array and remove the "),n("code",[t._v("trial_days")]),t._v(" configuration option that is within the billable configuration array:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'user'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'model'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 'trial_days' => 5, Remove this configuration option...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'trial_days'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("p",[t._v("Now, after a billable model's initial registration, the "),n("code",[t._v("trialDays")]),t._v(" method provided by the model instance will return "),n("code",[t._v("false")]),t._v(". You may examine the results of the "),n("code",[t._v("subscribed")]),t._v(" method to conditionally show an alert to your user that they should select a subscription plan before beginning to use your application. For example, if you are using the Blade templating language:")]),t._v(" "),n("div",{staticClass:"language-html extra-class"},[n("pre",{pre:!0,attrs:{class:"language-html"}},[n("code",[t._v("@if (! Auth::user()->subscribed())\n "),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("div")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n You must "),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("a")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("href")]),n("span",{pre:!0,attrs:{class:"token attr-value"}},[n("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("/billing"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("select a subscription plan"),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v(" before continuing.\n "),n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n@endif\n")])])]),n("h2",{attrs:{id:"determining-plan-eligibility"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-plan-eligibility"}},[t._v("#")]),t._v(" Determining Plan Eligibility")]),t._v(" "),n("p",[t._v("Sometimes, you may wish to place limitations on a particular billing plan. For example, a project management application might limit users on a particular billing plan to a maximum of 10 projects, while a higher priced plan might allow the creation of up to 20 projects.")]),t._v(" "),n("p",[t._v("If you choose to take this approach to billing, you will need to instruct Spark how to determine if a given billable model is eligible to be placed on a particular billing plan. You may accomplish this by modifying the "),n("code",[t._v("checkPlanEligibility")]),t._v(" callback registered within your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class. This callback will be invoked when a billable model attempts to subscribe to or switch to a new subscription plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Illuminate"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Validation"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("checkPlanEligibility")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name type-declaration"}},[t._v("Plan")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$plan")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("name")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Basic'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("throw")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("ValidationException")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("withMessages")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plan'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'You have too many projects for the selected plan.'")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"per-seat-billing-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#per-seat-billing-plans"}},[t._v("#")]),t._v(" Per-Seat Billing Plans")]),t._v(" "),n("p",[t._v('Some applications charge users per "seat" instead of a fixed monthly price. For example, a project management application might charge $10 monthly '),n("strong",[t._v("per project")]),t._v(" such that if a user managed five projects they would be billed $50 monthly.")]),t._v(" "),n("p",[t._v("If your application will be using per-seat billing, you will likely define a single, monthly plan in your application's "),n("code",[t._v("config/spark.php")]),t._v(' configuration file. In addition, you will need to instruct Spark how to calculate the current number of "seats" a billable model is currently using.')]),t._v(" "),n("p",[t._v('You may instruct Spark how to calculate the current number of "seats" a billable model is currently using via the '),n("code",[t._v("chargePerSeat")]),t._v(" method when configuring a billable model. Typically, this method should be called within the "),n("code",[t._v("boot")]),t._v(" method of your application's "),n("code",[t._v("App\\Providers\\SparkServiceProvider")]),t._v(" class:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("App"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Models"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("User")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token package"}},[t._v("Spark"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("Spark")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name static-context"}},[t._v("User")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("chargePerSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'project'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$billable")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("projects")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("p",[t._v("The first argument accepted by the "),n("code",[t._v("chargePerSeat")]),t._v(' method is the term that your application uses to refer to a "seat". In the case of a project management application, this would be a "project". The second argument given to the '),n("code",[t._v("chargePerSeat")]),t._v(' method should be a closure that accepts the billable model and returns the current number of "seats" occupied by that model.')]),t._v(" "),n("p",[t._v("After configuring per-seat billing, Spark will automatically update the wording within your application's billing portal to inform users that billing is calculated on a per-seat basis.")]),t._v(" "),n("h3",{attrs:{id:"incrementing-decrementing-the-seat-count"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#incrementing-decrementing-the-seat-count"}},[t._v("#")]),t._v(" Incrementing / Decrementing The Seat Count")]),t._v(" "),n("p",[t._v("The "),n("code",[t._v("chargePerSeat")]),t._v(" callback that was explained above will inform Spark of the current seat count that should be used when a customer initiates a subscription. However, you still need to inform Spark when to add or remove a seat when a user is using your application. For example, if building a project management application that bills per project, you would need to inform Spark when a user creates or deletes a project. You can accomplish this by calling the "),n("code",[t._v("addSeat")]),t._v(" and "),n("code",[t._v("removeSeat")]),t._v(" method:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("addSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("removeSeat")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),n("h2",{attrs:{id:"determining-subscription-status"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#determining-subscription-status"}},[t._v("#")]),t._v(" Determining Subscription Status")]),t._v(" "),n("p",[t._v("While building your application, you will often need to inspect a user's subscription status and plan to determine if they are allowed to perform a given action. For example, you may not want to let a user create a project if they are subscribed to a billing plan that only allows a specific number of projects to be created. First, you should review the "),n("RouterLink",{attrs:{to:"/2.x/spark-stripe/middleware.html"}},[t._v("subscription verification middleware")]),t._v(" provided by Spark.")],1),t._v(" "),n("p",[t._v("Additionally, you may always manually inspect a billable model's subscription status using the "),n("a",{attrs:{href:"https://laravel.com/docs/billing#checking-subscription-status",target:"_blank",rel:"noopener noreferrer"}},[t._v("methods provided by Laravel Cashier"),n("OutboundLink")],1),t._v(", which can be especially useful for verifying that a user is subscribed to a particular plan:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribed")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The user has an active subscription...")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscribedToPrice")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$planId")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// The user has a subscription to a plan with a Stripe plan / price ID of "price_id"...')]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"defining-plan-incentive-text"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#defining-plan-incentive-text"}},[t._v("#")]),t._v(" Defining Plan Incentive Text")]),t._v(" "),n("p",[t._v('Spark allows you to define plan "incentive" text to display to your users. For example, you may wish to display the amount saved by choosing to use a yearly plan vs. a monthly plan. Incentive text is shown in the top right corner of the plan\'s card:')]),t._v(" "),n("p",[n("img",{attrs:{src:s(347),alt:"Incentive text example"}})]),t._v(" "),n("p",[t._v("To define incentive text, you may add "),n("code",[t._v("monthly_incentive")]),t._v(" and / or "),n("code",[t._v("yearly_incentive")]),t._v(" configuration options to your plan definition:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_incentive'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Save 10%'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 1'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 2'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Feature 3'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"access-a-billable-s-spark-plan"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#access-a-billable-s-spark-plan"}},[t._v("#")]),t._v(" Access A Billable's Spark Plan")]),t._v(" "),n("p",[t._v("Sometimes you may wish to access the Spark plan instance for a given billable in order to determine what options are available to the plan. For example, if your plan definition contains the following:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'short_description'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'This is a short, human friendly description of the plan.'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'monthly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'yearly_id'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'price_id'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'features'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'options'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("p",[t._v("You may access the plan and options like so:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$canCreateBackups")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("sparkPlan")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token property"}},[t._v("options")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'database_backups'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("??")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("false")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"archiving-plans"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#archiving-plans"}},[t._v("#")]),t._v(" Archiving Plans")]),t._v(" "),n("p",[t._v('If you plan to "archive" or retire a particular plan for your application, you should add the '),n("code",[t._v("archived")]),t._v(" configuration option to the plan's configuration array. You should not completely remove the plan's configuration if existing users of your application that have already subscribed to the plan will be allowed to continue their subscription:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'plans'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'name'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'Standard'")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string single-quoted-string"}},[t._v("'archived'")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token constant boolean"}},[t._v("true")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n")])])]),n("h2",{attrs:{id:"account-deletion"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#account-deletion"}},[t._v("#")]),t._v(" Account Deletion")]),t._v(" "),n("p",[t._v("If your application allows users to completely delete their account data, you should ensure that you cancel any subscription plans that the user has subscribed to before you delete their data. Otherwise, the user may continue to be billed even after you have deleted their data. You may cancel their subscription using "),n("a",{attrs:{href:"https://laravel.com/docs/billing",target:"_blank",rel:"noopener noreferrer"}},[t._v("Laravel Cashier's"),n("OutboundLink")],1),t._v(" typical subscription management methods. Depending on the billable types used by your application, you may need to adjust this code to your application's unique needs:")]),t._v(" "),n("div",{staticClass:"language-php extra-class"},[n("pre",{pre:!0,attrs:{class:"language-php"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("optional")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("recurring")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$user")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("subscription")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("cancelNow")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/.vuepress/dist/assets/js/app.f3c199dd.js b/.vuepress/dist/assets/js/app.95651ca8.js similarity index 82% rename from .vuepress/dist/assets/js/app.f3c199dd.js rename to .vuepress/dist/assets/js/app.95651ca8.js index e7433b2..9cc2471 100644 --- a/.vuepress/dist/assets/js/app.f3c199dd.js +++ b/.vuepress/dist/assets/js/app.95651ca8.js @@ -1,4 +1,4 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[]]);!function(t){function e(e){for(var r,a,s=e[0],u=e[1],c=e[2],f=0,p=[];f=n.length?{value:void 0,done:!0}:(t=r(n,o),e.index+=t.length,{value:t,done:!1})}))},function(t,e,n){var r=n(159),o="object"==typeof self&&self&&self.Object===Object&&self,i=r||o||Function("return this")();t.exports=i},function(t,e,n){var r=n(2),o=r({}.toString),i=r("".slice);t.exports=function(t){return i(o(t),8,-1)}},function(t,e,n){var r,o=n(7),i=n(125),a=n(93),s=n(44),u=n(129),c=n(62),l=n(67),f=l("IE_PROTO"),p=function(){},d=function(t){return" + diff --git a/.vuepress/dist/index.html b/.vuepress/dist/index.html index bd7b5ea..04fd5f4 100644 --- a/.vuepress/dist/index.html +++ b/.vuepress/dist/index.html @@ -13,8 +13,8 @@ - - + + - + diff --git a/2.x/spark-stripe/upgrade.md b/2.x/spark-stripe/upgrade.md index 2915a75..9109158 100644 --- a/2.x/spark-stripe/upgrade.md +++ b/2.x/spark-stripe/upgrade.md @@ -14,6 +14,7 @@ The following required dependency versions have been updated: - The minimum Laravel version is now v9.0 - The minimum PHP version is now v8.0 - The minimum Stripe SDK version is now v7.39 +- The minimum VatCalculator version is now v3.0 ### Stripe API Version @@ -46,6 +47,10 @@ You may use the following upgrade checklist to properly enable to the new webhoo After following this process, your new webhook will be active and ready to receive events. +### VatCalculator v3 + +[VatCalculator](https://github.com/driesvints/vat-calculator) was upgraded to its latest major version, v3. While there shouldn't be any breaking changes for Spark, you might want to review its [upgrade guide](https://github.com/driesvints/vat-calculator/blob/3.x/UPGRADE.md), specifically the section on [removed countries](https://github.com/driesvints/vat-calculator/blob/3.x/UPGRADE.md#removed-countries) for tax calculations. + ### Renaming "Plans" To Prices To accommodate Stripe's phasing out of the "Plans" API, we've made the choice to partially migrate away from the "Plans" terminology. Because of this, the `stripe_plan` columns on the `subscriptions` and `subscription_items` tables have been renamed to `stripe_price`. You will need to write a migration to rename these columns: From 441ce471b06d3d58163e057c365d68519ab434c4 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 12 Apr 2022 08:57:50 -0500 Subject: [PATCH 2/2] Update upgrade.md --- 2.x/spark-stripe/upgrade.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/2.x/spark-stripe/upgrade.md b/2.x/spark-stripe/upgrade.md index 9109158..43d70df 100644 --- a/2.x/spark-stripe/upgrade.md +++ b/2.x/spark-stripe/upgrade.md @@ -47,9 +47,9 @@ You may use the following upgrade checklist to properly enable to the new webhoo After following this process, your new webhook will be active and ready to receive events. -### VatCalculator v3 +### VatCalculator 3.x -[VatCalculator](https://github.com/driesvints/vat-calculator) was upgraded to its latest major version, v3. While there shouldn't be any breaking changes for Spark, you might want to review its [upgrade guide](https://github.com/driesvints/vat-calculator/blob/3.x/UPGRADE.md), specifically the section on [removed countries](https://github.com/driesvints/vat-calculator/blob/3.x/UPGRADE.md#removed-countries) for tax calculations. +The [VatCalculator](https://github.com/driesvints/vat-calculator) package utilized by Spark has been upgraded to its latest major version. While we do not anticipate any breaking changes from this upgrade, you might want to review this package's [upgrade guide](https://github.com/driesvints/vat-calculator/blob/3.x/UPGRADE.md), specifically the section on [removed countries](https://github.com/driesvints/vat-calculator/blob/3.x/UPGRADE.md#removed-countries). ### Renaming "Plans" To Prices