Browse Source

Setup subscription SQL table

Includes the associated Go functions for inserting and selecting given a
specific user ID or subscription ID. Also adds required HTML tags and
HTTP queries for subscription process during user registration.
master
Immanuel Onyeka 1 year ago
parent
commit
51e46a2ce6
9 changed files with 233 additions and 1 deletions
  1. +1
    -0
      go.mod
  2. +14
    -0
      go.sum
  3. +1
    -1
      grav-admin/user/js/registration/account.vue
  4. +13
    -0
      grav-admin/user/js/registration/billing.vue
  5. +3
    -0
      grav-admin/user/js/registration/registration.vue
  6. +1
    -0
      grav-admin/user/themes/quark/templates/partials/base.html.twig
  7. +11
    -0
      migrations/0_29092022_setup_tables.sql
  8. +1
    -0
      migrations/reset.sql
  9. +188
    -0
      skouter.go

+ 1
- 0
go.mod View File

@@ -9,4 +9,5 @@ require (
github.com/dustin/go-humanize v1.0.1
github.com/go-sql-driver/mysql v1.6.0
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/stripe/stripe-go/v76 v76.12.0
)

+ 14
- 0
go.sum View File

@@ -2,6 +2,7 @@ github.com/SebastiaanKlippert/go-wkhtmltopdf v1.9.0 h1:DNrExYwvyyI404SxdUCCANAj9
github.com/SebastiaanKlippert/go-wkhtmltopdf v1.9.0/go.mod h1:SQq4xfIdvf6WYKSDxAJc+xOJdolt+/bc1jnQKMtPMvQ=
github.com/brianvoe/gofakeit/v6 v6.23.2 h1:lVde18uhad5wII/f5RMVFLtdQNE0HaGFuBUXmYKk8i8=
github.com/brianvoe/gofakeit/v6 v6.23.2/go.mod h1:Ow6qC71xtwm79anlwKRlWZW6zVq9D2XHE4QSSMP/rU8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/disintegration/gift v1.2.1 h1:Y005a1X4Z7Uc+0gLpSAsKhWi4qLtsdEcMIbbdvdZ6pc=
github.com/disintegration/gift v1.2.1/go.mod h1:Jh2i7f7Q2BM7Ezno3PhfezbR1xpUg9dUg3/RlKGr4HI=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
@@ -10,3 +11,16 @@ github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfC
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stripe/stripe-go/v76 v76.12.0 h1:TzkkQ1yXEZqO8+WS4Qun/mYKRLFQpPX8bti3VUEoe30=
github.com/stripe/stripe-go/v76 v76.12.0/go.mod h1:rw1MxjlAKKcZ+3FOXgTHgwiOa2ya6CPq6ykpJ0Q6Po4=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 1
- 1
grav-admin/user/js/registration/account.vue View File

@@ -64,7 +64,7 @@ import { ref } from "vue"
import Dropdown from "./dropdown.vue"

const addresses = ref([])
const user = ref({})
const user = ref({country: "USA", title: "Loan Officer"})
const address = ref({})
const locationsId = ref(null)
const props = defineProps(['err'])


+ 13
- 0
grav-admin/user/js/registration/billing.vue View File

@@ -0,0 +1,13 @@
<template>
<div>

<h4>hello</h4>

</div>
</template>

<script setup>
import { ref } from "vue"

let stripe = Stripe(process.env.STRIPE_KEY)
</script>

+ 3
- 0
grav-admin/user/js/registration/registration.vue View File

@@ -2,18 +2,21 @@
<section class="shadowbox">
<h2>Register</h2>
<account v-if="!step" :err="err" @submit="create" />
<billing v-if="step" :err="err" @submit="create" />
</section>
</template>

<script setup>
import { ref } from "vue"
import Account from "./account.vue"
import Billing from "./billing.vue"

let err = ref("")
const step = ref(0)

function create(user) {
console.log(user)
fetch(`/api/user`,
{method: 'POST',
body: JSON.stringify(user),


+ 1
- 0
grav-admin/user/themes/quark/templates/partials/base.html.twig View File

@@ -27,6 +27,7 @@
{% endblock %}

{% block javascripts %}
<script src="https://js.stripe.com/v3/"></script>
{% do assets.addJs('jquery', 101) %}
{% do assets.addJs('theme://js/jquery.treemenu.js', {group:'bottom'}) %}
{% do assets.addJs('theme://js/site.js', {group:'bottom'}) %}


+ 11
- 0
migrations/0_29092022_setup_tables.sql View File

@@ -56,6 +56,17 @@ CREATE TABLE user (
FOREIGN KEY (address) REFERENCES address(id)
);

CREATE TABLE subscription (
id INT AUTO_INCREMENT,
stripe_id VARCHAR(255) DEFAULT '',
user_id INT,
customer_id VARCHAR(255) NOT NULL,
current_period_end INT DEFAULT 0,
current_period_start INT DEFAULT 0,
PRIMARY KEY (`id`),
FOREIGN KEY (user_id) REFERENCES user(id)
);

CREATE TABLE license (
id INT AUTO_INCREMENT,
user_id INT NOT NULL,


+ 1
- 0
migrations/reset.sql View File

@@ -8,6 +8,7 @@ DROP TABLE IF EXISTS borrower;
DROP TABLE IF EXISTS estimate;
DROP TABLE IF EXISTS loan_type;
DROP TABLE IF EXISTS license;
DROP TABLE IF EXISTS subscription;
DROP TABLE IF EXISTS user;
DROP TABLE IF EXISTS branch;
DROP TABLE IF EXISTS address;

+ 188
- 0
skouter.go View File

@@ -28,6 +28,10 @@ import (
"github.com/disintegration/gift"
"github.com/dustin/go-humanize"
"github.com/golang-jwt/jwt/v4"
"github.com/stripe/stripe-go/v76"
"github.com/stripe/stripe-go/v76/customer"
"github.com/stripe/stripe-go/v76/subscription"
// "github.com/stripe/stripe-go/v76/paymentintent"
"image"
_ "image/jpeg"
"image/png"
@@ -59,6 +63,16 @@ type Branch struct {
Address Address `json:"address"`
}

type Subscription struct {
Id int `json:"id"`
UserId int `json:"userId"`
StripeId string `json:"stripeId"`
CustomerId string `json:"customerId"`
Start int `json:"start"`
End int `json:"end"`
ClientSecret string `json:"clientSecret,omitempty"`
}

type User struct {
Id int `json:"id"`
Email string `json:"email"`
@@ -68,12 +82,14 @@ type User struct {
Address Address `json:"address"`
Branch Branch `json:"branch"`
License License `json:"license"`
Sub Subscription `json:"sub"`
Status string `json:"status"`
Country string `json:"country"`
Title string `json:"title"`
Verified bool `json:"verified"`
Role string `json:"role"`
Password string `json:"password,omitempty"`
CustomerId string `json:"customerId"`
}

type License struct {
@@ -1107,6 +1123,7 @@ func queryUser(db *sql.DB, id int) (User, error) {
u.country,
u.title,
coalesce(u.status, ''),
coalesce(u.customer_id, '')
u.verified,
u.role,
u.address,
@@ -1128,6 +1145,7 @@ func queryUser(db *sql.DB, id int) (User, error) {
&user.Country,
&user.Title,
&user.Status,
&user.CustomerId,
&user.Verified,
&user.Role,
&user.Address.Id,
@@ -1222,6 +1240,60 @@ func queryUsers(db *sql.DB, id int) ([]User, error) {
return users, nil
}

func querySub(db *sql.DB, id int) (Subscription, error) {
var query string
var err error
var s Subscription

query = `SELECT
id,
stripe_id,
user_id,
customer_id,
current_period_end,
current_period_start
FROM subscription WHERE id = ?
`
row := db.QueryRow(query, id)

err = row.Scan(
&s.Id,
&s.StripeId,
&s.CustomerId,
&s.End,
&s.Start,
)

return s, err
}

func (user *User) querySub(db *sql.DB) error {
var query string
var err error

query = `SELECT
id,
stripe_id,
user_id,
customer_id,
current_period_end,
current_period_start
FROM subscription WHERE user_id = ?
`
row := db.QueryRow(query, user.Id)

err = row.Scan(
&user.Sub.Id,
&user.Sub.StripeId,
&user.Sub.UserId,
&user.Sub.CustomerId,
&user.Sub.End,
&user.Sub.Start,
)

return err
}

func (estimate *Estimate) insertResults(db *sql.DB) error {
var query string
var row *sql.Row
@@ -1322,6 +1394,51 @@ func insertUser(db *sql.DB, user User) (int, error) {
return id, nil
}

// Insert user returning it's ID or any error
func (sub *Subscription) insertSub(db *sql.DB) (error) {
var query string
var err error

query = `INSERT INTO subscription
(
stripe_id,
user_id,
customer_id,
current_period_end,
current_period_start
)
VALUES (?, ?, ?, ?, ?)
`

_, err = db.Exec(query,
sub.StripeId,
sub.UserId,
sub.CustomerId,
sub.End,
sub.Start,
)

return err
}


// Updates a user's stripe customer ID.
func (user *User) updateCustomerId(db *sql.DB, cid string) (error) {
var query string
var err error

query = `UPDATE user SET
customer_id = ?
WHERE id = ?
`
_, err = db.Exec(query,
cid,
user.Id,
)

return err
}

func updateAddress(address Address, db *sql.DB) error {
query := `
UPDATE address
@@ -1378,12 +1495,14 @@ func getUser(w http.ResponseWriter, db *sql.DB, r *http.Request) {
w.WriteHeader(500)
return
}
user, err := queryUser(db, claims.Id)
if err != nil {
w.WriteHeader(422)
log.Println(err)
return
}
json.NewEncoder(w).Encode(user)
}

@@ -2731,6 +2850,74 @@ func clipLetterhead(w http.ResponseWriter, db *sql.DB, r *http.Request) {
}
}

func createCustomer(name string, email string, address Address) (
stripe.Customer, error) {

params := &stripe.CustomerParams{
Email: stripe.String(email),
Name: stripe.String(name),
Address: &stripe.AddressParams{
City: stripe.String(address.City),
Country: stripe.String(address.Country),
Line1: stripe.String(address.Street),
PostalCode: stripe.String(address.Zip),
State: stripe.String(address.Region),
},
};
result, err := customer.New(params)
return *result, err
}

func createSubscription(w http.ResponseWriter, db *sql.DB, r *http.Request) {
claims, err := getClaims(r)
user, err := queryUser(db, claims.Id)
if err != nil {
w.WriteHeader(422)
return
}
var name string = user.FirstName + " " + user.LastName
c, err := createCustomer(name, user.Email, user.Address)
if err != nil {
http.Error(w, err.Error(), 422)
return
}
err = user.updateCustomerId(db, c.ID)
// Automatically save the payment method to the subscription
// when the first payment is successful.
paymentSettings := &stripe.SubscriptionPaymentSettingsParams{
SaveDefaultPaymentMethod: stripe.String("on_subscription"),
}
// Create the subscription. Note we're expanding the Subscription's
// latest invoice and that invoice's payment_intent
// so we can pass it to the front end to confirm the payment
subscriptionParams := &stripe.SubscriptionParams{
Customer: stripe.String(c.ID),
Items: []*stripe.SubscriptionItemsParams{
{
Price: stripe.String("price_1OZLK9BPMoXn2pf9kuTAf8rs"),
},
},
PaymentSettings: paymentSettings,
PaymentBehavior: stripe.String("default_incomplete"),
}
subscriptionParams.AddExpand("latest_invoice.payment_intent")
s, err := subscription.New(subscriptionParams)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
json.NewEncoder(w).Encode(s)
}

func api(w http.ResponseWriter, r *http.Request) {
var args []string

@@ -3176,6 +3363,7 @@ func dev(args []string) {
os.Setenv("DBName", "skouter_dev")
os.Setenv("DBUser", "tester")
os.Setenv("DBPass", "test123")
stripe.Key = os.Getenv("STRIPE_SECRET_KEY")

db, err := sql.Open("mysql",
fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/%s?multiStatements=true",


Loading…
Cancel
Save