variants units
This commit is contained in:
@@ -3,37 +3,40 @@ package models
|
||||
import "time"
|
||||
|
||||
type Customers struct {
|
||||
Customerid int `json:"customerid" gorm:"Primary_Key"`
|
||||
Firstname string `json:"firstname"`
|
||||
Lastname string `json:"lastname"`
|
||||
Profileimage string `json:"profileimage"`
|
||||
Gender string `json:"gender"`
|
||||
Dob string `json:"dob"`
|
||||
Dialcode string `json:"dialcode"`
|
||||
Contactno string `json:"contactno"`
|
||||
Email string `json:"email"`
|
||||
Deviceid string `json:"deviceid"`
|
||||
Devicetype string `json:"devicetype"`
|
||||
Authmode int `json:"authmode"`
|
||||
Configid int `json:"configid"`
|
||||
Customertoken string `json:"customertoken"`
|
||||
Address string `json:"address"`
|
||||
Suburb string `json:"suburb"`
|
||||
City string `json:"city"`
|
||||
State string `json:"state"`
|
||||
Landmark string `json:"landmark"`
|
||||
Doorno string `json:"doorno"`
|
||||
Postcode string `json:"postcode"`
|
||||
Latitude string `json:"latitude"`
|
||||
Longitude string `json:"longitude"`
|
||||
Applocationid int `json:"applocationid"`
|
||||
Locationid int `json:"locationid,omitempty" gorm:"-"`
|
||||
Defaultaddress string `json:"defaultaddress,omitempty" gorm:"-"`
|
||||
Primaryaddress int `json:"primaryaddress,omitempty" gorm:"-"`
|
||||
Tenantid int `json:"tenantid,omitempty" gorm:"-"`
|
||||
Status int `json:"status"`
|
||||
Intro string `json:"intro"`
|
||||
Qrmode int `json:"qrmode,omitempty" gorm:"-"`
|
||||
Customerid int `json:"customerid" gorm:"Primary_Key"`
|
||||
Firstname string `json:"firstname"`
|
||||
Lastname string `json:"lastname"`
|
||||
Profileimage string `json:"profileimage"`
|
||||
Gender string `json:"gender"`
|
||||
Dob string `json:"dob"`
|
||||
Dialcode string `json:"dialcode"`
|
||||
Contactno string `json:"contactno"`
|
||||
Email string `json:"email"`
|
||||
Deviceid string `json:"deviceid"`
|
||||
Devicetype string `json:"devicetype"`
|
||||
Authmode int `json:"authmode"`
|
||||
Configid int `json:"configid"`
|
||||
Customertoken string `json:"customertoken"`
|
||||
Address string `json:"address"`
|
||||
Suburb string `json:"suburb"`
|
||||
City string `json:"city"`
|
||||
State string `json:"state"`
|
||||
Landmark string `json:"landmark"`
|
||||
Doorno string `json:"doorno"`
|
||||
Postcode string `json:"postcode"`
|
||||
// Numbers from a map picker, strings from a text field — see
|
||||
// Customerlocations below. A customer must exist before an order can be
|
||||
// placed, so a 400 here blocks the whole flow, not just the address.
|
||||
Latitude FlexibleString `json:"latitude"`
|
||||
Longitude FlexibleString `json:"longitude"`
|
||||
Applocationid int `json:"applocationid"`
|
||||
Locationid int `json:"locationid,omitempty" gorm:"-"`
|
||||
Defaultaddress string `json:"defaultaddress,omitempty" gorm:"-"`
|
||||
Primaryaddress int `json:"primaryaddress,omitempty" gorm:"-"`
|
||||
Tenantid int `json:"tenantid,omitempty" gorm:"-"`
|
||||
Status int `json:"status"`
|
||||
Intro string `json:"intro"`
|
||||
Qrmode int `json:"qrmode,omitempty" gorm:"-"`
|
||||
}
|
||||
|
||||
type CustomerInfo struct {
|
||||
@@ -82,20 +85,37 @@ type CustomerLocationResult struct {
|
||||
}
|
||||
|
||||
type Customerlocations struct {
|
||||
Locationid int `json:"locationid" gorm:"Primary_Key"`
|
||||
Customerid int `json:"customerid"`
|
||||
Applocationid int `json:"applocationid" gorm:"-"`
|
||||
Address string `json:"address"`
|
||||
Suburb string `json:"suburb"`
|
||||
City string `json:"city"`
|
||||
State string `json:"state"`
|
||||
Landmark string `json:"landmark"`
|
||||
Doorno string `json:"doorno"`
|
||||
Postcode string `json:"postcode"`
|
||||
Latitude string `json:"latitude"`
|
||||
Longitude string `json:"longitude"`
|
||||
Primaryaddress int `json:"primaryaddress"`
|
||||
Status int `json:"status"`
|
||||
Locationid int `json:"locationid" gorm:"Primary_Key"`
|
||||
Customerid int `json:"customerid"`
|
||||
// The query joins customers to select b.applocationid; `gorm:"-"` then threw
|
||||
// it away, so every address came back with 0 however the join resolved.
|
||||
Applocationid int `json:"applocationid" gorm:"->"`
|
||||
Address string `json:"address"`
|
||||
Suburb string `json:"suburb"`
|
||||
City string `json:"city"`
|
||||
State string `json:"state"`
|
||||
Landmark string `json:"landmark"`
|
||||
Doorno string `json:"doorno"`
|
||||
Postcode string `json:"postcode"`
|
||||
// Latitude and longitude arrive as NUMBERS from a map picker and as strings
|
||||
// from a text field. A strict type rejected the first, and BodyParser fails
|
||||
// the WHOLE request on one unreadable field — so a shopper who set their
|
||||
// location on a map got 400 and no saved address. Same treatment the order
|
||||
// model already gives Pickuplat and Pickuplong.
|
||||
Latitude FlexibleString `json:"latitude"`
|
||||
Longitude FlexibleString `json:"longitude"`
|
||||
|
||||
// A "make this my default" checkbox sends true, a form sends 1, a text
|
||||
// input sends "1". All three mean the same thing.
|
||||
Primaryaddress FlexibleInt `json:"primaryaddress"`
|
||||
|
||||
// Sent as 1, as "1", or as the word "Active", depending on the caller.
|
||||
Status FlexibleInt `json:"status"`
|
||||
|
||||
// Selected by GetCustomerLocations and, until now, dropped on the floor:
|
||||
// the struct had no field for it, so the column marking the chosen address
|
||||
// never reached the app.
|
||||
Defaultaddress string `json:"defaultaddress"`
|
||||
}
|
||||
|
||||
type CustomerRequest struct {
|
||||
|
||||
116
models/flexibleInt.go
Normal file
116
models/flexibleInt.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// FlexibleInt is an integer column that accepts what clients actually send.
|
||||
//
|
||||
// The counterpart to FlexibleString, and it exists for the same reason: a strict
|
||||
// type here does not reject one field, it rejects the WHOLE request. Fiber's
|
||||
// BodyParser fails on the first field it cannot convert, so `"status": "Active"`
|
||||
// or `"primaryaddress": true` returns 400 "Invalid request body" and nothing is
|
||||
// saved. On the address form that surfaced as a shopper adding a delivery
|
||||
// address, seeing no error worth acting on, and then finding no address to pick
|
||||
// at checkout — measured 2026-09-02: three plausible payloads, three 400s.
|
||||
//
|
||||
// Accepted, in the shapes a form or a phone actually produces:
|
||||
//
|
||||
// 1 a number
|
||||
// "1" a number as a string, which is what a text input gives
|
||||
// true a checkbox — "set as my default address"
|
||||
// "" an untouched field, read as 0 rather than an error
|
||||
// "Active" a word, mapped by meaning: active/yes/true/default are 1
|
||||
//
|
||||
// A word it does not recognise is an error, not a silent 0. Guessing there
|
||||
// would store something the shopper did not choose.
|
||||
type FlexibleInt int
|
||||
|
||||
func (fi *FlexibleInt) UnmarshalJSON(b []byte) error {
|
||||
if len(b) == 0 || string(b) == "null" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if b[0] == '"' {
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
*fi = 0
|
||||
return nil
|
||||
}
|
||||
if n, err := strconv.Atoi(s); err == nil {
|
||||
*fi = FlexibleInt(n)
|
||||
return nil
|
||||
}
|
||||
switch strings.ToLower(s) {
|
||||
case "active", "yes", "true", "default", "primary":
|
||||
*fi = 1
|
||||
case "inactive", "no", "false":
|
||||
*fi = 0
|
||||
default:
|
||||
return fmt.Errorf("cannot read %q as a number", s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if b[0] == 't' || b[0] == 'f' {
|
||||
var v bool
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
if v {
|
||||
*fi = 1
|
||||
} else {
|
||||
*fi = 0
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A number, possibly written with a decimal point by a client that has no
|
||||
// integer type of its own.
|
||||
var f float64
|
||||
if err := json.Unmarshal(b, &f); err != nil {
|
||||
return err
|
||||
}
|
||||
*fi = FlexibleInt(int(f))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fi FlexibleInt) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(int(fi))
|
||||
}
|
||||
|
||||
// Scan reads the column back. bigint arrives as int64; the string cases cover a
|
||||
// text column that holds a number, which this schema has in places.
|
||||
func (fi *FlexibleInt) Scan(value interface{}) error {
|
||||
switch v := value.(type) {
|
||||
case nil:
|
||||
*fi = 0
|
||||
case int64:
|
||||
*fi = FlexibleInt(v)
|
||||
case int:
|
||||
*fi = FlexibleInt(v)
|
||||
case float64:
|
||||
*fi = FlexibleInt(int(v))
|
||||
case []byte:
|
||||
n, _ := strconv.Atoi(strings.TrimSpace(string(v)))
|
||||
*fi = FlexibleInt(n)
|
||||
case string:
|
||||
n, _ := strconv.Atoi(strings.TrimSpace(v))
|
||||
*fi = FlexibleInt(n)
|
||||
default:
|
||||
return fmt.Errorf("cannot read %T as a number", value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fi FlexibleInt) Value() (driver.Value, error) {
|
||||
return int64(fi), nil
|
||||
}
|
||||
88
models/flexibleInt_test.go
Normal file
88
models/flexibleInt_test.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
/*
|
||||
A strict type on one field rejects the whole request.
|
||||
|
||||
Fiber's BodyParser stops at the first field it cannot convert and returns 400
|
||||
"Invalid request body" — so `"primaryaddress": true` from a checkbox threw away
|
||||
the address, the street and the pincode with it. The shopper saw no error worth
|
||||
acting on and then had no address to choose at checkout.
|
||||
|
||||
Measured 2026-09-02 against the running backend: three plausible payloads for
|
||||
one address form, three 400s.
|
||||
*/
|
||||
|
||||
func readInt(t *testing.T, body string) (FlexibleInt, error) {
|
||||
t.Helper()
|
||||
var v struct {
|
||||
N FlexibleInt `json:"n"`
|
||||
}
|
||||
err := json.Unmarshal([]byte(`{"n":`+body+`}`), &v)
|
||||
return v.N, err
|
||||
}
|
||||
|
||||
func mustRead(t *testing.T, body string, want FlexibleInt) {
|
||||
t.Helper()
|
||||
got, err := readInt(t, body)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", body, err)
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("%s -> %d, want %d", body, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestACheckboxIsANumber(t *testing.T) {
|
||||
// "Set as my default address" sends a boolean.
|
||||
mustRead(t, "true", 1)
|
||||
mustRead(t, "false", 0)
|
||||
}
|
||||
|
||||
func TestATextInputIsANumber(t *testing.T) {
|
||||
mustRead(t, `"1"`, 1)
|
||||
mustRead(t, `"0"`, 0)
|
||||
}
|
||||
|
||||
func TestAWordIsReadByMeaning(t *testing.T) {
|
||||
mustRead(t, `"Active"`, 1)
|
||||
mustRead(t, `"active"`, 1)
|
||||
mustRead(t, `"Inactive"`, 0)
|
||||
}
|
||||
|
||||
func TestAnUntouchedFieldIsZeroNotAnError(t *testing.T) {
|
||||
mustRead(t, `""`, 0)
|
||||
mustRead(t, "null", 0)
|
||||
}
|
||||
|
||||
func TestAClientWithNoIntegerTypeStillWorks(t *testing.T) {
|
||||
// JavaScript has one number type, so 1 can arrive as 1.0.
|
||||
mustRead(t, "1.0", 1)
|
||||
}
|
||||
|
||||
func TestAWordItCannotReadIsRefusedRatherThanGuessed(t *testing.T) {
|
||||
// Storing 0 for something unrecognised would record a choice the shopper
|
||||
// never made. Better to fail loudly than to invent an answer.
|
||||
if _, err := readInt(t, `"maybe"`); err == nil {
|
||||
t.Error(`"maybe" was silently accepted`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLatitudeSurvivesBothShapes(t *testing.T) {
|
||||
// A map picker sends a number; a text field sends a string. Both are the
|
||||
// same place, and rejecting either loses the whole address.
|
||||
var withNumber, withString Customerlocations
|
||||
if err := json.Unmarshal([]byte(`{"latitude":11.0168}`), &withNumber); err != nil {
|
||||
t.Fatalf("number latitude: %v", err)
|
||||
}
|
||||
if err := json.Unmarshal([]byte(`{"latitude":"11.0168"}`), &withString); err != nil {
|
||||
t.Fatalf("string latitude: %v", err)
|
||||
}
|
||||
if withNumber.Latitude != withString.Latitude {
|
||||
t.Errorf("%q from a number, %q from a string", withNumber.Latitude, withString.Latitude)
|
||||
}
|
||||
}
|
||||
@@ -63,9 +63,14 @@ type Productvariant struct {
|
||||
// why a variant does not need to duplicate any of them.
|
||||
Variantproductid int `json:"variantproductid"`
|
||||
|
||||
Variantname string `json:"variantname"`
|
||||
Varianttype string `json:"varianttype,omitempty"`
|
||||
Price float64 `json:"price,omitempty"`
|
||||
Variantname string `json:"variantname"`
|
||||
Varianttype string `json:"varianttype,omitempty"`
|
||||
|
||||
// A per-variant price override. 0 means "no override, use the product’s
|
||||
// own price" — which is a real answer, so it is always emitted. With
|
||||
// omitempty the key vanished at 0 and a client reading `price` got
|
||||
// undefined, then rendered it.
|
||||
Price float64 `json:"price"`
|
||||
|
||||
Categoryid int `json:"categoryid" gorm:"default:0"`
|
||||
Categoryname string `json:"categoryname" gorm:"-"`
|
||||
@@ -78,6 +83,12 @@ type Productvariant struct {
|
||||
Variantproductname string `json:"variantproductname" gorm:"->"`
|
||||
Variantprice float64 `json:"variantprice" gorm:"->"`
|
||||
Variantstock int `json:"variantstock" gorm:"->"`
|
||||
|
||||
// The size, as the product itself records it. Without these the only way to
|
||||
// label a size was to join the parent’s unit fields to the variant’s name,
|
||||
// which is how "null kg" reaches a screen.
|
||||
Variantunitvalue string `json:"variantunitvalue" gorm:"->"`
|
||||
Variantproductunit string `json:"variantproductunit" gorm:"->"`
|
||||
}
|
||||
|
||||
type Products struct {
|
||||
@@ -131,8 +142,8 @@ type Products struct {
|
||||
Productsku string `json:"productsku,omitempty"`
|
||||
Brandid int `json:"brandid,omitempty"`
|
||||
Productbrand string `json:"productbrand,omitempty"`
|
||||
Productunit string `json:"productunit,omitempty"`
|
||||
Unitvalue string `json:"unitvalue,omitempty"`
|
||||
Productunit string `json:"productunit"`
|
||||
Unitvalue string `json:"unitvalue"`
|
||||
Toppicks string `json:"toppicks,omitempty"`
|
||||
Productcost float64 `json:"productcost,omitempty"`
|
||||
Taxamount float64 `json:"taxamount,omitempty"`
|
||||
@@ -163,7 +174,7 @@ type Products struct {
|
||||
// returned only Retailprice, which the admin catalogue never writes.
|
||||
// Same meaning as Locationproducts.Price, so both product feeds agree.
|
||||
Price float64 `json:"price" gorm:"->"`
|
||||
Retailprice float64 `json:"retailprice,omitempty"`
|
||||
Retailprice float64 `json:"retailprice"`
|
||||
Diffprice float64 `json:"diffprice,omitempty"`
|
||||
Diffpercent float64 `json:"diffpercent,omitempty"`
|
||||
Othercost float64 `json:"othercost,omitempty"`
|
||||
@@ -199,8 +210,8 @@ type Locationproducts struct {
|
||||
Productsku string `json:"productsku,omitempty"`
|
||||
Brandid int `json:"brandid,omitempty"`
|
||||
Productbrand string `json:"productbrand,omitempty"`
|
||||
Productunit string `json:"productunit,omitempty"`
|
||||
Unitvalue string `json:"unitvalue,omitempty"`
|
||||
Productunit string `json:"productunit"`
|
||||
Unitvalue string `json:"unitvalue"`
|
||||
Toppicks string `json:"toppicks,omitempty"`
|
||||
Productcost float64 `json:"productcost,omitempty"`
|
||||
Taxamount float64 `json:"taxamount,omitempty"`
|
||||
@@ -215,7 +226,7 @@ type Locationproducts struct {
|
||||
// productlocations row, not from products. Without it a store could set a
|
||||
// price and never read it back, so the UI always showed the master price.
|
||||
Price float64 `json:"price" gorm:"->"`
|
||||
Retailprice float64 `json:"retailprice,omitempty"`
|
||||
Retailprice float64 `json:"retailprice"`
|
||||
Diffprice float64 `json:"diffprice,omitempty"`
|
||||
Diffpercent float64 `json:"diffpercent,omitempty"`
|
||||
Othercost float64 `json:"othercost,omitempty"`
|
||||
|
||||
71
models/productWire_test.go
Normal file
71
models/productWire_test.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
/*
|
||||
A missing string must reach a client as "", never as an absent key.
|
||||
|
||||
`unitvalue` and `productunit` were both `omitempty`, and on this platform
|
||||
`unitvalue` is empty for every product — measured 2026-09-02 on R mart: 24
|
||||
products, 0 with both fields, 7 with a unit and no value. So the key vanished
|
||||
from the JSON, a client read `undefined`, and joining it to the unit rendered
|
||||
the literal text "null kg" on a shopper's screen.
|
||||
|
||||
The same applies to money: a price of 0 is a real answer ("this has no price
|
||||
set"), and a client that receives no key at all cannot tell that from a field
|
||||
it forgot to request.
|
||||
*/
|
||||
|
||||
func fieldsOf(t *testing.T, v any) map[string]any {
|
||||
t.Helper()
|
||||
raw, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal: %v", err)
|
||||
}
|
||||
var out map[string]any
|
||||
if err := json.Unmarshal(raw, &out); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func TestAnEmptyUnitIsSentAsEmptyNotOmitted(t *testing.T) {
|
||||
got := fieldsOf(t, Products{Productid: 1})
|
||||
for _, key := range []string{"unitvalue", "productunit"} {
|
||||
if _, present := got[key]; !present {
|
||||
t.Errorf("%q was omitted; a client reads that as null and renders it", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAZeroPriceIsSentAsZeroNotOmitted(t *testing.T) {
|
||||
got := fieldsOf(t, Products{Productid: 1})
|
||||
if _, present := got["retailprice"]; !present {
|
||||
t.Error("retailprice was omitted; 0 is a real answer and must be visible")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAVariantAlwaysCarriesItsPriceAndUnit(t *testing.T) {
|
||||
got := fieldsOf(t, Productvariant{Variantid: 1})
|
||||
for _, key := range []string{"price", "variantprice", "variantunitvalue", "variantproductunit"} {
|
||||
if _, present := got[key]; !present {
|
||||
t.Errorf("variant option omitted %q", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAProductWithNoVariantsSendsAnEmptyListNotNull(t *testing.T) {
|
||||
// The case that lets an order proceed: [] means "order this one directly".
|
||||
// A JSON null would force every client to null-check before counting.
|
||||
got := fieldsOf(t, Products{Productid: 1, Variantoptions: []Productvariant{}})
|
||||
list, ok := got["variantoptions"].([]any)
|
||||
if !ok {
|
||||
t.Fatalf("variantoptions was %T, want a list", got["variantoptions"])
|
||||
}
|
||||
if len(list) != 0 {
|
||||
t.Errorf("expected an empty list, got %d", len(list))
|
||||
}
|
||||
}
|
||||
@@ -224,8 +224,8 @@ func (r *deliveriesRepository) UpdateDelivery(data models.UpdateDeliveryStatus)
|
||||
|
||||
case "picked":
|
||||
if data.Pickuplocationid != 0 && data.Deliverytype != "B" {
|
||||
cloc.Latitude = data.Riderslat
|
||||
cloc.Longitude = data.Riderslon
|
||||
cloc.Latitude = models.FlexibleString(data.Riderslat)
|
||||
cloc.Longitude = models.FlexibleString(data.Riderslon)
|
||||
cloc.Address = data.Address
|
||||
cloc.Suburb = data.Suburb
|
||||
cloc.City = data.City
|
||||
@@ -247,8 +247,8 @@ func (r *deliveriesRepository) UpdateDelivery(data models.UpdateDeliveryStatus)
|
||||
}
|
||||
|
||||
if data.Deliverylocationid != 0 && data.Deliverytype != "B" {
|
||||
cloc.Latitude = data.Deliverylat
|
||||
cloc.Longitude = data.Deliverylong
|
||||
cloc.Latitude = models.FlexibleString(data.Deliverylat)
|
||||
cloc.Longitude = models.FlexibleString(data.Deliverylong)
|
||||
cloc.Address = data.Address
|
||||
cloc.Suburb = data.Suburb
|
||||
cloc.City = data.City
|
||||
|
||||
@@ -123,7 +123,14 @@ func (r *productRepository) VariantsForProducts(tenantid, locationid int, produc
|
||||
Select(`
|
||||
v.*,
|
||||
p.productname AS variantproductname,
|
||||
COALESCE(NULLIF((
|
||||
COALESCE(p.unitvalue, '') AS variantunitvalue,
|
||||
COALESCE(p.productunit, '') AS variantproductunit,
|
||||
-- The variant’s own override wins, then the outlet’s price, then the
|
||||
-- master price. The override was being ignored entirely: a size
|
||||
-- priced differently from its product was sold at the product’s
|
||||
-- price. NULLIF because 0 in that column means "no override", not
|
||||
-- "free".
|
||||
COALESCE(NULLIF(v.price, 0), NULLIF((
|
||||
SELECT pl.price FROM productlocations pl
|
||||
WHERE pl.productid = v.variantproductid AND pl.tenantid = v.tenantid AND pl.locationid = ?
|
||||
LIMIT 1
|
||||
|
||||
@@ -695,8 +695,8 @@ func (r *tenantRepository) CreateTenantUser(data models.Tenants) (bool, error) {
|
||||
cust.State = data.State
|
||||
cust.Postcode = data.Postcode
|
||||
cust.Applocationid = data.Applocationid
|
||||
cust.Latitude = data.Latitude
|
||||
cust.Longitude = data.Longitude
|
||||
cust.Latitude = models.FlexibleString(data.Latitude)
|
||||
cust.Longitude = models.FlexibleString(data.Longitude)
|
||||
cust.Primaryaddress = 1
|
||||
|
||||
cid := r.CheckCustomer(data.Primarycontact)
|
||||
|
||||
Reference in New Issue
Block a user