166 lines
3.7 KiB
Go
166 lines
3.7 KiB
Go
package orders
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"google.golang.org/api/option"
|
|
"google.golang.org/api/sheets/v4"
|
|
)
|
|
|
|
const (
|
|
tab = "Zamówienia"
|
|
statusPending = "oczekuje"
|
|
statusConfirmed = "potwierdzone"
|
|
)
|
|
|
|
var (
|
|
sheetsSvc *sheets.Service
|
|
SheetID string
|
|
rowMu sync.Mutex
|
|
)
|
|
|
|
func init() {
|
|
SheetID = os.Getenv("SHEET_ID")
|
|
credsFile := os.Getenv("SHEETS_CREDS")
|
|
var err error
|
|
sheetsSvc, err = sheets.NewService(context.Background(), option.WithCredentialsFile(credsFile))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
log.Println("init google sheets")
|
|
}
|
|
|
|
func sctx() (context.Context, context.CancelFunc) {
|
|
return context.WithTimeout(context.Background(), 10*time.Second)
|
|
}
|
|
|
|
func cell(r []any, i int) string {
|
|
if i < len(r) && r[i] != nil {
|
|
return strings.TrimSpace(fmt.Sprint(r[i]))
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func get(ctx context.Context, a1 string) ([][]any, error) {
|
|
res, err := sheetsSvc.Spreadsheets.Values.Get(SheetID, a1).Context(ctx).Do()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return res.Values, nil
|
|
}
|
|
|
|
func clearRow(ctx context.Context, row int) error {
|
|
_, err := sheetsSvc.Spreadsheets.Values.BatchClear(SheetID, &sheets.BatchClearValuesRequest{
|
|
Ranges: []string{
|
|
fmt.Sprintf("%s!B%d:D%d", tab, row, row),
|
|
fmt.Sprintf("%s!G%d", tab, row),
|
|
fmt.Sprintf("%s!I%d:T%d", tab, row, row),
|
|
},
|
|
}).Context(ctx).Do()
|
|
return err
|
|
}
|
|
|
|
func insertPending(o order) (string, error) {
|
|
ctx, cancel := sctx()
|
|
defer cancel()
|
|
rowMu.Lock()
|
|
defer rowMu.Unlock()
|
|
|
|
vals, err := get(ctx, tab+"!B:C")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
row := max(len(vals)+1, 4)
|
|
for i := 3; i < len(vals); i++ {
|
|
if cell(vals[i], 0) == "" && cell(vals[i], 1) == "" {
|
|
row = i + 1
|
|
break
|
|
}
|
|
}
|
|
|
|
data := []*sheets.ValueRange{{
|
|
Range: fmt.Sprintf("%s!B%d:D%d", tab, row, row),
|
|
Values: [][]any{{o.phone, o.name, statusPending}},
|
|
}}
|
|
for _, it := range o.items {
|
|
if it.count > 0 {
|
|
data = append(data, &sheets.ValueRange{
|
|
Range: fmt.Sprintf("%s!%s%d", tab, it.id, row),
|
|
Values: [][]any{{float64(it.count) / 10}},
|
|
})
|
|
}
|
|
}
|
|
_, err = sheetsSvc.Spreadsheets.Values.BatchUpdate(SheetID, &sheets.BatchUpdateValuesRequest{
|
|
ValueInputOption: "RAW",
|
|
Data: data,
|
|
}).Context(ctx).Do()
|
|
if err != nil {
|
|
for _, datum := range data {
|
|
log.Println(datum)
|
|
}
|
|
return "", err
|
|
}
|
|
|
|
idVals, err := get(ctx, fmt.Sprintf("%s!A%d", tab, row))
|
|
if err != nil || len(idVals) == 0 || cell(idVals[0], 0) == "" {
|
|
clearRow(ctx, row)
|
|
return "", errors.New("row has no id")
|
|
}
|
|
return cell(idVals[0], 0), nil
|
|
}
|
|
|
|
func findPendingRow(ctx context.Context, id string) (int, error) {
|
|
ids, err := get(ctx, tab+"!A:A")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
for i, r := range ids {
|
|
if i == 0 || cell(r, 0) != id {
|
|
continue
|
|
}
|
|
row := i + 1
|
|
v, err := get(ctx, fmt.Sprintf("%s!D%d", tab, row))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if len(v) > 0 && cell(v[0], 0) == statusPending {
|
|
return row, nil
|
|
}
|
|
return 0, errors.New("row is not pending")
|
|
}
|
|
return 0, errors.New("no row with this id")
|
|
}
|
|
|
|
func confirmRow(id string) error {
|
|
ctx, cancel := sctx()
|
|
defer cancel()
|
|
row, err := findPendingRow(ctx, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = sheetsSvc.Spreadsheets.Values.BatchUpdate(SheetID, &sheets.BatchUpdateValuesRequest{
|
|
ValueInputOption: "RAW",
|
|
Data: []*sheets.ValueRange{
|
|
{Range: fmt.Sprintf("%s!D%d", tab, row), Values: [][]any{{statusConfirmed}}},
|
|
{Range: fmt.Sprintf("%s!G%d", tab, row), Values: [][]any{{float64(retainer) / 100}}},
|
|
},
|
|
}).Context(ctx).Do()
|
|
return err
|
|
}
|
|
|
|
func clearOrder(id string) error {
|
|
ctx, cancel := sctx()
|
|
defer cancel()
|
|
row, err := findPendingRow(ctx, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return clearRow(ctx, row)
|
|
}
|