add timezone to org

This commit is contained in:
Patrick Nagurny
2019-06-27 16:43:18 -04:00
parent 12bca2cb1f
commit a67f270b6d
5 changed files with 123 additions and 6 deletions

View File

@@ -22,6 +22,7 @@ import (
* @apiSuccess {String} name Name of the Org. * @apiSuccess {String} name Name of the Org.
* @apiSuccess {String} currency Three letter currency code. * @apiSuccess {String} currency Three letter currency code.
* @apiSuccess {Number} precision How many digits the currency goes out to. * @apiSuccess {Number} precision How many digits the currency goes out to.
* @apiSuccess {String} timezone Timezone to use for accounting.
* *
* @apiSuccessExample Success-Response: * @apiSuccessExample Success-Response:
* HTTP/1.1 200 OK * HTTP/1.1 200 OK
@@ -32,6 +33,7 @@ import (
* "name": "MyOrg", * "name": "MyOrg",
* "currency": "USD", * "currency": "USD",
* "precision": 2, * "precision": 2,
* "timezone": "America/New_York"
* } * }
* *
* @apiUse NotAuthorizedError * @apiUse NotAuthorizedError
@@ -66,6 +68,7 @@ func GetOrg(w rest.ResponseWriter, r *rest.Request) {
* @apiSuccess {String} name Name of the Org. * @apiSuccess {String} name Name of the Org.
* @apiSuccess {String} currency Three letter currency code. * @apiSuccess {String} currency Three letter currency code.
* @apiSuccess {Number} precision How many digits the currency goes out to. * @apiSuccess {Number} precision How many digits the currency goes out to.
@apiSuccess {String} timezone Timezone to use for accounting.
* *
* @apiSuccessExample Success-Response: * @apiSuccessExample Success-Response:
* HTTP/1.1 200 OK * HTTP/1.1 200 OK
@@ -77,6 +80,7 @@ func GetOrg(w rest.ResponseWriter, r *rest.Request) {
* "name": "MyOrg", * "name": "MyOrg",
* "currency": "USD", * "currency": "USD",
* "precision": 2, * "precision": 2,
* "timezone": "America/New_York"
* } * }
* ] * ]
* *
@@ -109,6 +113,7 @@ func GetOrgs(w rest.ResponseWriter, r *rest.Request) {
* @apiParam {String} name Name of the Org. * @apiParam {String} name Name of the Org.
* @apiParam {String} currency Three letter currency code. * @apiParam {String} currency Three letter currency code.
* @apiParam {Number} precision How many digits the currency goes out to. * @apiParam {Number} precision How many digits the currency goes out to.
* @apiParam {String} timezone Timezone to use for accounting.
* *
* @apiSuccess {String} id Id of the Org. * @apiSuccess {String} id Id of the Org.
* @apiSuccess {Date} inserted Date Org was created * @apiSuccess {Date} inserted Date Org was created
@@ -116,6 +121,7 @@ func GetOrgs(w rest.ResponseWriter, r *rest.Request) {
* @apiSuccess {String} name Name of the Org. * @apiSuccess {String} name Name of the Org.
* @apiSuccess {String} currency Three letter currency code. * @apiSuccess {String} currency Three letter currency code.
* @apiSuccess {Number} precision How many digits the currency goes out to. * @apiSuccess {Number} precision How many digits the currency goes out to.
* @apiSuccess {String} timezone Timezone to use for accounting.
* *
* @apiSuccessExample Success-Response: * @apiSuccessExample Success-Response:
* HTTP/1.1 200 OK * HTTP/1.1 200 OK
@@ -126,6 +132,7 @@ func GetOrgs(w rest.ResponseWriter, r *rest.Request) {
* "name": "MyOrg", * "name": "MyOrg",
* "currency": "USD", * "currency": "USD",
* "precision": 2, * "precision": 2,
* "timezone": "America/New_York"
* } * }
* *
* @apiUse NotAuthorizedError * @apiUse NotAuthorizedError
@@ -167,6 +174,7 @@ func PostOrg(w rest.ResponseWriter, r *rest.Request) {
* @apiSuccess {String} name Name of the Org. * @apiSuccess {String} name Name of the Org.
* @apiSuccess {String} currency Three letter currency code. * @apiSuccess {String} currency Three letter currency code.
* @apiSuccess {Number} precision How many digits the currency goes out to. * @apiSuccess {Number} precision How many digits the currency goes out to.
* @apiSuccess {String} timezone Timezone to use for accounting.
* *
* @apiSuccessExample Success-Response: * @apiSuccessExample Success-Response:
* HTTP/1.1 200 OK * HTTP/1.1 200 OK
@@ -177,6 +185,7 @@ func PostOrg(w rest.ResponseWriter, r *rest.Request) {
* "name": "MyOrg", * "name": "MyOrg",
* "currency": "USD", * "currency": "USD",
* "precision": 2, * "precision": 2,
* "timezone": "America/New_York"
* } * }
* *
* @apiUse NotAuthorizedError * @apiUse NotAuthorizedError

View File

@@ -21,7 +21,7 @@ type OrgInterface interface {
DeleteInvite(string) error DeleteInvite(string) error
} }
const orgFields = "LOWER(HEX(o.id)),o.inserted,o.updated,o.name,o.currency,o.`precision`" const orgFields = "LOWER(HEX(o.id)),o.inserted,o.updated,o.name,o.currency,o.`precision`,o.timezone"
const inviteFields = "i.id,LOWER(HEX(i.orgId)),i.inserted,i.updated,i.email,i.accepted" const inviteFields = "i.id,LOWER(HEX(i.orgId)),i.inserted,i.updated,i.email,i.accepted"
func (db *DB) CreateOrg(org *types.Org, userId string, accounts []*types.Account) (err error) { func (db *DB) CreateOrg(org *types.Org, userId string, accounts []*types.Account) (err error) {
@@ -46,7 +46,7 @@ func (db *DB) CreateOrg(org *types.Org, userId string, accounts []*types.Account
org.Updated = org.Inserted org.Updated = org.Inserted
// create org // create org
query1 := "INSERT INTO org(id,inserted,updated,name,currency,`precision`) VALUES(UNHEX(?),?,?,?,?,?)" query1 := "INSERT INTO org(id,inserted,updated,name,currency,`precision`,timezone) VALUES(UNHEX(?),?,?,?,?,?,?)"
res, err := tx.Exec( res, err := tx.Exec(
query1, query1,
@@ -56,6 +56,7 @@ func (db *DB) CreateOrg(org *types.Org, userId string, accounts []*types.Account
org.Name, org.Name,
org.Currency, org.Currency,
org.Precision, org.Precision,
org.Timezone,
) )
if err != nil { if err != nil {
@@ -126,11 +127,12 @@ func (db *DB) CreateOrg(org *types.Org, userId string, accounts []*types.Account
func (db *DB) UpdateOrg(org *types.Org) error { func (db *DB) UpdateOrg(org *types.Org) error {
org.Updated = time.Now() org.Updated = time.Now()
query := "UPDATE org SET updated = ?, name = ? WHERE id = UNHEX(?)" query := "UPDATE org SET updated = ?, name = ?, timezone = ? WHERE id = UNHEX(?)"
_, err := db.Exec( _, err := db.Exec(
query, query,
util.TimeToMs(org.Updated), util.TimeToMs(org.Updated),
org.Name, org.Name,
org.Timezone,
org.Id, org.Id,
) )
@@ -143,7 +145,7 @@ func (db *DB) GetOrg(orgId string, userId string) (*types.Org, error) {
var updated int64 var updated int64
err := db.QueryRow("SELECT "+orgFields+" FROM org o JOIN userorg ON userorg.orgId = o.id WHERE o.id = UNHEX(?) AND userorg.userId = UNHEX(?)", orgId, userId). err := db.QueryRow("SELECT "+orgFields+" FROM org o JOIN userorg ON userorg.orgId = o.id WHERE o.id = UNHEX(?) AND userorg.userId = UNHEX(?)", orgId, userId).
Scan(&o.Id, &inserted, &updated, &o.Name, &o.Currency, &o.Precision) Scan(&o.Id, &inserted, &updated, &o.Name, &o.Currency, &o.Precision, &o.Timezone)
switch { switch {
case err == sql.ErrNoRows: case err == sql.ErrNoRows:
@@ -173,7 +175,7 @@ func (db *DB) GetOrgs(userId string) ([]*types.Org, error) {
var inserted int64 var inserted int64
var updated int64 var updated int64
err = rows.Scan(&o.Id, &inserted, &updated, &o.Name, &o.Currency, &o.Precision) err = rows.Scan(&o.Id, &inserted, &updated, &o.Name, &o.Currency, &o.Precision, &o.Timezone)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -11,4 +11,5 @@ type Org struct {
Name string `json:"name"` Name string `json:"name"`
Currency string `json:"currency"` Currency string `json:"currency"`
Precision int `json:"precision"` Precision int `json:"precision"`
Timezone string `json:"timezone"`
} }

105
migrations/migrate2.go Normal file
View File

@@ -0,0 +1,105 @@
package main
import (
"encoding/json"
"github.com/openaccounting/oa-server/core/model/db"
"github.com/openaccounting/oa-server/core/model/types"
"log"
"os"
)
func main() {
if len(os.Args) != 2 {
log.Fatal("Usage: migrate2.go <upgrade/downgrade>")
}
command := os.Args[1]
if command != "upgrade" && command != "downgrade" {
log.Fatal("Usage: migrate2.go <upgrade/downgrade>")
}
//filename is the path to the json config file
var config types.Config
file, err := os.Open("./config.json")
if err != nil {
log.Fatal(err)
}
decoder := json.NewDecoder(file)
err = decoder.Decode(&config)
if err != nil {
log.Fatal(err)
}
connectionString := config.User + ":" + config.Password + "@/" + config.Database
db, err := db.NewDB(connectionString)
if command == "upgrade" {
err = upgrade(db)
} else {
err = downgrade(db)
}
if err != nil {
log.Fatal(err)
}
log.Println("done")
}
func upgrade(db *db.DB) (err error) {
tx, err := db.Begin()
if err != nil {
return
}
defer func() {
if p := recover(); p != nil {
tx.Rollback()
panic(p) // re-throw panic after Rollback
} else if err != nil {
tx.Rollback()
} else {
err = tx.Commit()
}
}()
query1 := "ALTER TABLE org ADD COLUMN timezone VARCHAR(100) NOT NULL AFTER `precision`"
if _, err = tx.Exec(query1); err != nil {
return
}
return
}
func downgrade(db *db.DB) (err error) {
tx, err := db.Begin()
if err != nil {
return
}
defer func() {
if p := recover(); p != nil {
tx.Rollback()
panic(p) // re-throw panic after Rollback
} else if err != nil {
tx.Rollback()
} else {
err = tx.Commit()
}
}()
query1 := "ALTER TABLE org DROP COLUMN timezone"
if _, err = tx.Exec(query1); err != nil {
return
}
return
}

View File

@@ -4,7 +4,7 @@ CREATE DATABASE openaccounting CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
use openaccounting; use openaccounting;
CREATE TABLE org (id BINARY(16) NOT NULL, inserted BIGINT UNSIGNED NOT NULL, updated BIGINT UNSIGNED NOT NULL, name VARCHAR(100) NOT NULL, currency VARCHAR(10) NOT NULL, `precision` INT NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB; CREATE TABLE org (id BINARY(16) NOT NULL, inserted BIGINT UNSIGNED NOT NULL, updated BIGINT UNSIGNED NOT NULL, name VARCHAR(100) NOT NULL, currency VARCHAR(10) NOT NULL, `precision` INT NOT NULL, timezone VARCHAR(100) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB;
CREATE TABLE user (id BINARY(16) NOT NULL, inserted BIGINT UNSIGNED NOT NULL, updated BIGINT UNSIGNED NOT NULL, firstName VARCHAR(50) NOT NULL, lastName VARCHAR(50) NOT NULL, email VARCHAR(100) NOT NULL, passwordHash VARCHAR(100) NOT NULL, agreeToTerms BOOLEAN NOT NULL, passwordReset VARCHAR(32) NOT NULL, emailVerified BOOLEAN NOT NULL, emailVerifyCode VARCHAR(32) NOT NULL, signupSource VARCHAR(100) NOT NULL, UNIQUE(email), PRIMARY KEY(id)) ENGINE=InnoDB; CREATE TABLE user (id BINARY(16) NOT NULL, inserted BIGINT UNSIGNED NOT NULL, updated BIGINT UNSIGNED NOT NULL, firstName VARCHAR(50) NOT NULL, lastName VARCHAR(50) NOT NULL, email VARCHAR(100) NOT NULL, passwordHash VARCHAR(100) NOT NULL, agreeToTerms BOOLEAN NOT NULL, passwordReset VARCHAR(32) NOT NULL, emailVerified BOOLEAN NOT NULL, emailVerifyCode VARCHAR(32) NOT NULL, signupSource VARCHAR(100) NOT NULL, UNIQUE(email), PRIMARY KEY(id)) ENGINE=InnoDB;