diff --git a/app/account-services.go b/app/account-services.go index f8167db..d036196 100644 --- a/app/account-services.go +++ b/app/account-services.go @@ -4,40 +4,42 @@ import ( "fmt" "code.tnxs.net/taxnexus/lib/api/crm/crm_client/accounts" + "code.tnxs.net/taxnexus/lib/api/geo/geo_client/coordinate" + "code.tnxs.net/taxnexus/lib/api/geo/geo_models" ) // GetAccount is first class retrieval function -func GetAccount(key string, principal *User) Account { +func GetAccount(key string, principal *User) *Account { if key == "" { - return Account{} + return nil } a, ok := accountCache.get(key) if ok { - return *a + return a } acct, err := GetAccountByID(key, principal) if err != nil { - return Account{} + return nil } return acct } // GetAccountByID is first class retrieval function -func GetAccountByID(recordID string, principal *User) (Account, error) { +func GetAccountByID(recordID string, principal *User) (*Account, error) { sugar.Debug("app.GetAccountByID: 📥") if recordID == "" { - return Account{}, fmt.Errorf("app.getAccountByID: 💣 ⛔ key is blank") + return nil, fmt.Errorf("app.getAccountByID: 💣 ⛔ key is blank") } obj, ok := accountCache.get(recordID) if ok { sugar.Debug("app.getAccountByID: 👍 🎯 📤") - return *obj, nil + return obj, nil } crmParams := accounts.NewGetAccountsParamsWithTimeout(getTimeout) crmParams.AccountID = &recordID response, err := crmClient.Accounts.GetAccounts(crmParams, principal.Auth) if err != nil { - return Account{}, err + return nil, err } var newObj *Account for _, itm := range response.Payload.Data { // single iteration execution @@ -45,5 +47,44 @@ func GetAccountByID(recordID string, principal *User) (Account, error) { } accountCache.put(recordID, newObj) sugar.Debug("app.getAccountByID: 👍 🆕 📤") - return *newObj, nil + return newObj, nil +} + +// GetCoordinate is a first class retrieval function +func (obj *Account) GetCoordinate(principal *User) *Coordinate { + sugar.Debug("app.Account.getCoordinate: 📥") + if obj.CoordinateID != "" { // if CoordinateID is set, then just get it + geoParams := coordinate.NewGetCoordinatesParamsWithTimeout(getTimeout) + geoParams.CoordinateID = &obj.CoordinateID + response, err := geoClient.Coordinate.GetCoordinates(geoParams, principal.Auth) + if err != nil { + return nil + } + var obj *Coordinate + for _, itm := range response.Payload.Data { // single iteration execution + obj = UnMarshalCoordinate(itm, principal) + } + return obj + } // else get it via addresses, shipping #1, Business #2 + if obj.ShippingAddress.ToString() == "" && obj.BillingAddress.ToString() == "" { + sugar.Errorf("app.Account.getCoordinate: 💣 ⛔ billing and shipping address both blank") + return nil + } + theAddress := obj.ShippingAddress.ToString() + if theAddress == "" { + theAddress = obj.BillingAddress.ToString() + } + geoParams := coordinate.NewGetCoordinatesParamsWithTimeout(getTimeout) + geoParams.Address = &theAddress + response, err := geoClient.Coordinate.GetCoordinates(geoParams, principal.Auth) + if err != nil { + sugar.Error(err) + return nil + } + var swag *geo_models.Coordinate + for _, itm := range response.Payload.Data { // single iteration execution + swag = itm + } + sugar.Debug("app.Account.getCoordinate: 👍 📤") + return UnMarshalCoordinate(swag, principal) } diff --git a/app/account.go b/app/account.go index d2603ba..129a1ad 100644 --- a/app/account.go +++ b/app/account.go @@ -14,18 +14,23 @@ type AccountActivityWrapper struct { AdministrativeLevel string BillingAddress Address BillingContactID string + BillingContact Contact BillingPreference string BusinessAddress Address CannabisCustomer bool CompanyID string CoordinateID string + Coordinate Coordinate CustomerID string CustomerPriority string DBA string DefaultAddress Address DefaultBackendID string + DefaultBackend Backend DefaultDeliveryContactID string + DefaultDeliveryContact string DefaultEndUserID string + DefaultEndUser Contact Description string EIN string Email string @@ -35,6 +40,7 @@ type AccountActivityWrapper struct { MSPCustomer bool Name string OrderContactID string + OrderContact Contact OrderEmail string OwnerID string ParentID string @@ -45,6 +51,7 @@ type AccountActivityWrapper struct { Ref string ShippingAddress Address ShippingContactID string + ShippingContact Contact Site string TelecomCustomer bool TenantID string diff --git a/app/company-helpers.go b/app/company-helpers.go index f32ed17..eb73353 100644 --- a/app/company-helpers.go +++ b/app/company-helpers.go @@ -22,7 +22,7 @@ func ReMarshalCompany(p interface{}) crm_models.Company { } // UnMarshalCompany decodes swagger to first class object -func UnMarshalCompany(s *crm_models.Company) *Company { +func UnMarshalCompany(s *crm_models.Company, principal *User) *Company { if s.ID == "" { s.ID = uuid.New().String() } @@ -31,6 +31,7 @@ func UnMarshalCompany(s *crm_models.Company) *Company { dateClosed, e2 := time.Parse(dateTimeFormat, s.DateClosed) return &Company{ ID: s.ID, + BillingContact: GetContact(s.BillingContactID, principal), AccountID: s.AccountID, AccountNumberPrefix: s.AccountNumberPrefix, BillingAddress: UnMarshalCrmAddress(s.BillingAddress), @@ -45,6 +46,7 @@ func UnMarshalCompany(s *crm_models.Company) *Company { ColorPrimary: s.ColorPrimary, CreatedByID: s.CreatedByID, CustomerSuccessID: s.CustomerSuccessID, + CustomerSuccess: GetContact(s.CustomerSuccessID, principal), DefaultAddress: UnMarshalCrmAddress(s.DefaultAddress), DefaultCompany: s.DefaultCompany, FontBody: s.FontBody, @@ -59,9 +61,11 @@ func UnMarshalCompany(s *crm_models.Company) *Company { Logo: s.Logo, Name: s.Name, OwnerID: s.OwnerID, + Preparer: GetContact(s.PreparerID, principal), PreparerID: s.PreparerID, PricebookID: s.PricebookID, TenantID: s.TenantID, + UserTechLead: GetContact(s.UserTechLeadID, principal), UserTechLeadID: s.UserTechLeadID, CreatedDate: sql.NullTime{ Time: createdDate, diff --git a/app/company.go b/app/company.go index 6557f63..b731358 100644 --- a/app/company.go +++ b/app/company.go @@ -46,12 +46,14 @@ type CompanyActivityWrapper struct { // Company is a DB struct type Company struct { ID string + Account *Account AccountID string AccountNumberPrefix string AdvancePeriodID string BillingAddress *Address BillingAdvice string BillingContactID string + BillingContact *Contact BillingEmail string BillingPhone string BillingWebsite string @@ -65,6 +67,7 @@ type Company struct { CurrentPeriodID string CurrentPeriodStatus string CustomerSuccessID string + CustomerSuccess *Contact DateClosed sql.NullTime DefaultAddress *Address DefaultCompany bool @@ -81,8 +84,10 @@ type Company struct { Logo string Name string OwnerID string + Preparer *Contact PreparerID string PricebookID string TenantID string + UserTechLead *Contact UserTechLeadID string } diff --git a/app/contact-services.go b/app/contact-services.go index 278be2a..547b042 100644 --- a/app/contact-services.go +++ b/app/contact-services.go @@ -7,19 +7,19 @@ import ( ) // GetContact is a first class object retrieval function -func GetContact(id string, principal *User) Contact { +func GetContact(id string, principal *User) *Contact { if id == "" { - return Contact{} + return nil } c, ok := contactCache.get(id) if ok { - return *c + return c } c, err := GetContactByID(id, principal) if err != nil { - return Contact{} + return nil } - return *c + return c } // GetContactByID is a first class object retrieval function diff --git a/app/coordinate-helpers.go b/app/coordinate-helpers.go index d48e53d..6b4d325 100644 --- a/app/coordinate-helpers.go +++ b/app/coordinate-helpers.go @@ -7,7 +7,8 @@ import ( "code.tnxs.net/taxnexus/lib/api/geo/geo_models" ) -func UnMarshalSwaggerCoordinate(s *geo_models.Coordinate, principal *User) *Coordinate { +// UnMarshalCoordinate converts swagger to enriched first class object +func UnMarshalCoordinate(s *geo_models.Coordinate, principal *User) *Coordinate { taxTypes := []*TaxType{} for _, itm := range s.TaxTypes { if itm.ID != "" { diff --git a/app/render-float.go b/app/render-float.go index 3869a29..9ac1a85 100644 --- a/app/render-float.go +++ b/app/render-float.go @@ -33,7 +33,6 @@ which is convenient for calls within template. I didn't feel it was worth to publish a library just for this piece of code, hence the snippet. Feel free to reuse as you wish. -const rPattern = "#,###.##" */ import ( @@ -41,6 +40,8 @@ import ( "strconv" ) +const rPattern = "#,###.##" + var renderFloatPrecisionMultipliers = [10]float64{ 1, 10, diff --git a/app/root.go b/app/root.go index d0448b9..c68b1fa 100644 --- a/app/root.go +++ b/app/root.go @@ -29,6 +29,8 @@ var apiUsers map[string]User const getTimeout = 6 * time.Minute const postTimeout = 6 * time.Minute const constNotFound = "not found" +const percentFactor = 100 +const dateFormatDB = "2006-01-02" const dateFormat = "2006-01-02" const dateTimeFormat = "2006-01-02T15:04:05-0800" const dateTimeFormatAlt = "2006-01-02 15:04:05" diff --git a/app/stash-services.go b/app/stash-services.go index ed5d17a..ddde321 100644 --- a/app/stash-services.go +++ b/app/stash-services.go @@ -5,6 +5,7 @@ import ( "code.tnxs.net/taxnexus/lib/api/stash/stash_models" ) +// StashPDFParams is a param type type StashPDFParams struct { document *Document account *Account @@ -12,6 +13,7 @@ type StashPDFParams struct { principal *User } +// StashPDF stores a PDF in the stash database func StashPDF(params StashPDFParams) (*Document, error) { sugar.Debugf("render.stashPDF: 📥") var title string @@ -31,12 +33,8 @@ func StashPDF(params StashPDFParams) (*Document, error) { ref = "render.getTaxes" } - todoString := "todo" // todo #5 stashParams := stash_pdf.NewPostPdfsParamsWithTimeout(getTimeout) stashParams.PDFRequest = &stash_models.PDFRequest{ - Meta: &stash_models.RequestMeta{ - TaxnexusAccount: &todoString, - }, Data: []*stash_models.NewPDF{ { Description: description, diff --git a/app/taxtype-helpers.go b/app/taxtype-helpers.go index 56b9e72..ef2e8b9 100644 --- a/app/taxtype-helpers.go +++ b/app/taxtype-helpers.go @@ -2,6 +2,7 @@ package app import ( "database/sql" + "fmt" "time" "code.tnxs.net/taxnexus/lib/api/geo/geo_models" @@ -10,26 +11,49 @@ import ( // UnMarshalTaxType decodes swagger to a first class object func UnMarshalTaxType(s *geo_models.TaxType) *TaxType { + createdDate, _ := time.Parse(dateTimeFormat, s.CreatedDate) + lastModifiedDate, _ := time.Parse(dateTimeFormat, s.LastModifiedDate) + effectiveDate, _ := time.Parse(dateFormatDB, s.EffectiveDate) + endDate, _ := time.Parse(dateFormatDB, s.EndDate) + formatted := TaxTypeFormatted{ + CreatedDate: createdDate.Format(dateTimeFormat), + EffectiveDate: effectiveDate.Format(dateFormat), + EndDate: endDate.Format(dateFormat), + Fractional: fmt.Sprintf("%v", s.Fractional), + InterestRate: RenderFloat(rPattern, s.InterestRate*percentFactor) + "%", + IsMedicinal: fmt.Sprintf("%v", s.IsMedicinal), + IsRecreational: fmt.Sprintf("%v", s.IsRecreational), + LastModifiedDate: lastModifiedDate.Format(dateTimeFormat), + MarkupRate: RenderFloat(rPattern, (s.MarkupRate-1)*percentFactor) + "%", + PassThrough: fmt.Sprintf("%v", s.PassThrough), + PenaltyDays: fmt.Sprintf("%v", s.PenaltyDays), + PenaltyRate: RenderFloat(rPattern, s.PenaltyRate*percentFactor) + "%", + Rate: RenderFloat(rPattern, s.Rate*percentFactor) + "%", + } + switch { + case s.Category == "cannabis-ag": + formatted.Rate = "$" + RenderFloat(rPattern, s.Rate) + " / " + s.Units + } if s.ID == "" { s.ID = uuid.New().String() } dateTime, dateErr := time.Parse(dateTimeFormat, s.CreatedDate) - createdDate := sql.NullTime{ + createdDateSQL := sql.NullTime{ Time: dateTime, Valid: dateErr == nil, } dateTime, dateErr = time.Parse(dateTimeFormat, s.LastModifiedDate) - modifiedDate := sql.NullTime{ + modifiedDateSQL := sql.NullTime{ Time: dateTime, Valid: dateErr == nil, } date, dateErr := time.Parse(dateFormat, s.EffectiveDate) - effectiveDate := sql.NullTime{ + effectiveDateSQL := sql.NullTime{ Time: date, Valid: dateErr == nil, } date, dateErr = time.Parse(dateFormat, s.EndDate) - endDate := sql.NullTime{ + endDateSQL := sql.NullTime{ Time: date, Valid: dateErr == nil, } @@ -46,10 +70,10 @@ func UnMarshalTaxType(s *geo_models.TaxType) *TaxType { CompanyID: s.CompanyID, ContactID: s.ContactID, CreatedByID: s.CreatedByID, - CreatedDate: createdDate, + CreatedDate: createdDateSQL, Description: s.Description, - EffectiveDate: effectiveDate, - EndDate: endDate, + EffectiveDate: effectiveDateSQL, + EndDate: endDateSQL, EnrollmentStatus: s.EnrollmentStatus, FilingCity: s.FilingCity, FilingCountry: s.FilingCountry, @@ -58,6 +82,7 @@ func UnMarshalTaxType(s *geo_models.TaxType) *TaxType { FilingPostalcode: s.FilingPostalCode, FilingState: s.FilingState, FilingStreet: s.FilingStreet, + Formatted: formatted, Fractional: s.Fractional, Frequency: s.Frequency, GeocodeString: s.GeocodeString, @@ -65,7 +90,7 @@ func UnMarshalTaxType(s *geo_models.TaxType) *TaxType { IsMedicinal: s.IsMedicinal, IsRecreational: s.IsRecreational, LastModifiedByID: s.LastModifiedByID, - LastModifiedDate: modifiedDate, + LastModifiedDate: modifiedDateSQL, MarkupRate: s.MarkupRate, Name: s.Name, OwnerID: s.OwnerID, diff --git a/app/taxtype.go b/app/taxtype.go index eab6df4..20e51f0 100644 --- a/app/taxtype.go +++ b/app/taxtype.go @@ -42,7 +42,7 @@ type TaxType struct { FilingPostalcode string FilingState string FilingStreet string - Formatted taxTypeFormatted + Formatted TaxTypeFormatted Fractional bool Frequency string GeocodeString string @@ -70,7 +70,9 @@ type TaxType struct { UnitBase float64 Units string } -type taxTypeFormatted struct { + +// TaxTypeFormatted offers formatted versions of numerical values +type TaxTypeFormatted struct { CreatedDate string EffectiveDate string EndDate string