diff --git a/app/account-services.go b/app/account-services.go index d036196..2fb0c4c 100644 --- a/app/account-services.go +++ b/app/account-services.go @@ -24,7 +24,7 @@ func GetAccount(key string, principal *User) *Account { return acct } -// GetAccountByID is first class retrieval function +// GetAccountByID retrieves and enriches an Account object instance func GetAccountByID(recordID string, principal *User) (*Account, error) { sugar.Debug("app.GetAccountByID: 📥") if recordID == "" { @@ -41,13 +41,114 @@ func GetAccountByID(recordID string, principal *User) (*Account, error) { if err != nil { return nil, err } - var newObj *Account + var theObj *Account for _, itm := range response.Payload.Data { // single iteration execution - newObj = UnMarshalAccount(itm) + theObj = UnMarshalAccount(itm) } - accountCache.put(recordID, newObj) + finalObj := theObj.Enrich(principal) + accountCache.put(recordID, finalObj) sugar.Debug("app.getAccountByID: 👍 🆕 📤") - return newObj, nil + return finalObj, nil +} + +// Enrich adds subordinate objects to a first class object and returns a copy +func (obj *Account) Enrich(principal *User) *Account { + return &Account{ + ID: obj.ID, + AccountNumber: obj.AccountNumber, + AccountSource: obj.AccountSource, + Active: obj.Active, + AdministrativeLevel: obj.AdministrativeLevel, + Amount: obj.Amount, + AmountInvoiced: obj.AmountInvoiced, + AmountPaid: obj.AmountPaid, + AnnualRevenue: obj.AnnualRevenue, + Balance: obj.Balance, + BillingAddress: obj.BillingAddress, + BillingContactID: obj.BillingContactID, + BillingContact: GetContact(obj.BillingContactID, principal), + BillingPreference: obj.BillingPreference, + BusinessAddress: obj.BusinessAddress, + CannabisCustomer: obj.CannabisCustomer, + ChannelProgramLevelName: obj.ChannelProgramLevelName, + ChannelProgramName: obj.ChannelProgramName, + ClientEndDate: obj.ClientEndDate, + ClientStartDate: obj.ClientStartDate, + CompanyID: obj.CompanyID, + Coordinate: obj.GetCoordinate(principal), + CoordinateID: obj.CoordinateID, + CreatedByID: obj.CreatedByID, + CreatedDate: obj.CreatedDate, + CustomerID: obj.CustomerID, + CustomerPriority: obj.CustomerPriority, + DandBCompanyID: obj.DandBCompanyID, + DBA: obj.DBA, + DefaultAddress: obj.DefaultAddress, + DefaultBackendID: obj.DefaultBackendID, + DefaultBackend: GetBackend(obj.DefaultBackendID, principal), + DefaultDeliveryContactID: obj.DefaultDeliveryContactID, + DefaultEndUserID: obj.DefaultEndUserID, + DefaultEndUser: GetContact(obj.DefaultEndUserID, principal), + Description: obj.Description, + DunsNumber: obj.DunsNumber, + EIN: obj.EIN, + Email: obj.Email, + EnrollmentStatus: obj.EnrollmentStatus, + Fax: obj.Fax, + Industry: obj.Industry, + IsCustomerPortal: obj.IsCustomerPortal, + IsPartner: obj.IsPartner, + ISPCustomer: obj.ISPCustomer, + Jigsaw: obj.Jigsaw, + LastModifiedByID: obj.LastModifiedByID, + LastModifiedDate: obj.LastModifiedDate, + MSPCustomer: obj.MSPCustomer, + NaicsCode: obj.NaicsCode, + NaicsDesc: obj.NaicsDesc, + Name: obj.Name, + NumberOfEmployees: obj.NumberOfEmployees, + NumberOfLocations: obj.NumberOfLocations, + OpenCharges: obj.OpenCharges, + OrderContactID: obj.OrderContactID, + OrderContact: GetContact(obj.OrderContactID, principal), + OrderEmail: obj.OrderEmail, + OwnerID: obj.OwnerID, + Ownership: obj.Ownership, + ParentFK: obj.ParentFK, + ParentID: obj.ParentID, + Phone: obj.Phone, + PlaceID: obj.PlaceID, + PreparerID: obj.PreparerID, + Rating: obj.Rating, + RatingEngineID: obj.RatingEngineID, + Ref: obj.Ref, + RevenueBase: obj.RevenueBase, + RevenueNet: obj.RevenueNet, + RevenueNotTaxable: obj.RevenueNotTaxable, + ShippingAddress: obj.ShippingAddress, + ShippingCensusTract: obj.ShippingCensusTract, + ShippingContactID: obj.ShippingContactID, + ShippingContact: GetContact(obj.ShippingContactID, principal), + ShippingCounty: obj.ShippingCounty, + SIC: obj.SIC, + SicDesc: obj.SicDesc, + Site: obj.Site, + Status: obj.Status, + TaxExemption: obj.TaxExemption, + TaxOnTax: obj.TaxOnTax, + TelecomCustomer: obj.TelecomCustomer, + TenantID: obj.TenantID, + TickerSymbol: obj.TickerSymbol, + TradeStyle: obj.TradeStyle, + Type: obj.Type, + UnappliedPayments: obj.UnappliedPayments, + UnitBase: obj.UnitBase, + UpsellOpportunity: obj.UpsellOpportunity, + Website: obj.Website, + WHMCSClientID: obj.WHMCSClientID, + XeroContactID: obj.XeroContactID, + YearStarted: obj.YearStarted, + } } // GetCoordinate is a first class retrieval function diff --git a/app/account.go b/app/account.go index 2423372..1bf2aa9 100644 --- a/app/account.go +++ b/app/account.go @@ -93,6 +93,7 @@ type Account struct { DefaultBackend *Backend DefaultDeliveryContactID string DefaultEndUserID string + DefaultEndUser *Contact Description string DunsNumber string EIN string diff --git a/app/backend-cache.go b/app/backend-cache.go new file mode 100644 index 0000000..d682567 --- /dev/null +++ b/app/backend-cache.go @@ -0,0 +1,25 @@ +package app + +import "sync" + +var backendCache = backendCacheType{ + obj: map[string]*Backend{}, +} + +type backendCacheType struct { + sync.RWMutex + obj map[string]*Backend +} + +func (m *backendCacheType) get(recordID string) (*Backend, bool) { + m.RLock() + defer m.RUnlock() + r, ok := m.obj[recordID] + return r, ok +} + +func (m *backendCacheType) put(recordID string, itm *Backend) { + m.Lock() + defer m.Unlock() + m.obj[recordID] = itm +} diff --git a/app/backend-services.go b/app/backend-services.go new file mode 100644 index 0000000..6b05b1e --- /dev/null +++ b/app/backend-services.go @@ -0,0 +1,49 @@ +package app + +import ( + "fmt" + + "code.tnxs.net/taxnexus/lib/api/regs/regs_client/backend" +) + +// GetBackend is a first class object retrieval function +func GetBackend(id string, principal *User) *Backend { + if id == "" { + return nil + } + c, ok := backendCache.get(id) + if ok { + return c + } + c, err := GetBackendByID(id, principal) + if err != nil { + return nil + } + return c +} + +// GetBackendByID is a first class object retrieval function +func GetBackendByID(key string, principal *User) (*Backend, error) { + sugar.Debugf("app.getBackendByID: 📥") + if key == "" { + return nil, fmt.Errorf("app.getBackendByID: 💣 ⛔ key is blank") + } + obj, ok := backendCache.get(key) + if ok { + sugar.Debugf("app.getBackendByID: 👍 🎯 📤") + return obj, nil + } + params := backend.NewGetBackendsParamsWithTimeout(getTimeout) + params.BackendID = &key + response, err := regsClient.Backend.GetBackends(params, principal.Auth) + if err != nil { + return nil, err + } + var newObj *Backend + for _, itm := range response.Payload.Data { // single iteration execution + newObj = UnMarshalBackend(itm) + } + backendCache.put(key, newObj) + sugar.Debugf("app.getBackendByID: 👍 🆕 📤") + return newObj, nil +} diff --git a/app/company-cache.go b/app/company-cache.go index 23df5d7..504d57e 100644 --- a/app/company-cache.go +++ b/app/company-cache.go @@ -2,27 +2,25 @@ package app import ( "sync" - - "code.tnxs.net/taxnexus/lib/api/crm/crm_models" ) var companyCache = companyCacheType{ - obj: map[string]*crm_models.Company{}, + obj: map[string]*Company{}, } type companyCacheType struct { sync.RWMutex - obj map[string]*crm_models.Company + obj map[string]*Company } -func (m *companyCacheType) get(recordID string) (*crm_models.Company, bool) { +func (m *companyCacheType) get(recordID string) (*Company, bool) { m.RLock() defer m.RUnlock() r, ok := m.obj[recordID] return r, ok } -func (m *companyCacheType) put(recordID string, itm *crm_models.Company) { +func (m *companyCacheType) put(recordID string, itm *Company) { m.Lock() defer m.Unlock() m.obj[recordID] = itm diff --git a/app/company-services.go b/app/company-services.go index 154caa7..db7aaaf 100644 --- a/app/company-services.go +++ b/app/company-services.go @@ -4,11 +4,10 @@ import ( "fmt" "code.tnxs.net/taxnexus/lib/api/crm/crm_client/companies" - "code.tnxs.net/taxnexus/lib/api/crm/crm_models" ) // GetCompany is a first class object retrieval function -func GetCompany(id string, principal *User) *crm_models.Company { +func GetCompany(id string, principal *User) *Company { if id == "" { return nil } @@ -24,7 +23,7 @@ func GetCompany(id string, principal *User) *crm_models.Company { } // GetCompanyByID is a first class object retrieval function -func GetCompanyByID(key string, principal *User) (*crm_models.Company, error) { +func GetCompanyByID(key string, principal *User) (*Company, error) { sugar.Debugf("app.getCompanyByID: 📥") if key == "" { return nil, fmt.Errorf("app.getCompanyByID: 💣 ⛔ key is blank") @@ -40,18 +39,70 @@ func GetCompanyByID(key string, principal *User) (*crm_models.Company, error) { if err != nil { return nil, err } - var obj *crm_models.Company + var obj *Company for _, itm := range response.Payload.Data { // single iteration execution - obj = itm + obj = UnMarshalCompany(itm, principal) } - companyCache.put(key, obj) + finalObj := obj.Enrich(principal) + companyCache.put(key, finalObj) sugar.Debugf("app.getCompanyByID: 👍 🆕 📤") - return obj, nil + return finalObj, nil } const defaultCompanyID = "6ff8326f-79b7-40ae-afc7-390eca182b1b" // todo #3 Don't hardcode company ID // GetDefaultCompany returns the default company -func GetDefaultCompany(principal *User) *crm_models.Company { +func GetDefaultCompany(principal *User) *Company { return GetCompany(defaultCompanyID, principal) } + +// Enrich adds subordinate objects to a first class object and returns a copy +func (obj *Company) Enrich(principal *User) *Company { + return &Company{ + ID: obj.ID, + Account: GetAccount(obj.AccountID, principal), + AccountID: obj.AccountID, + AccountNumberPrefix: obj.AccountNumberPrefix, + AdvancePeriodID: obj.AdvancePeriodID, + BillingAddress: obj.BillingAddress, + BillingAdvice: obj.BillingAdvice, + BillingContactID: obj.BillingContactID, + BillingContact: GetContact(obj.BillingContactID, principal), + BillingEmail: obj.BillingEmail, + BillingPhone: obj.BillingPhone, + BillingWebsite: obj.BillingWebsite, + CoaTemplateID: obj.CoaTemplateID, + ColorAccent1: obj.ColorAccent1, + ColorAccent2: obj.ColorAccent2, + ColorPrimary: obj.ColorPrimary, + ClosedPeriodID: obj.ClosedPeriodID, + CreatedByID: obj.CreatedByID, + CreatedDate: obj.CreatedDate, + CurrentPeriodID: obj.CurrentPeriodID, + CurrentPeriodStatus: obj.CurrentPeriodStatus, + CustomerSuccessID: obj.CustomerSuccessID, + CustomerSuccess: GetContact(obj.CustomerSuccessID, principal), + DateClosed: obj.DateClosed, + DefaultAddress: obj.DefaultAddress, + DefaultCompany: obj.DefaultCompany, + FontBody: obj.FontBody, + FontHeading: obj.FontHeading, + FontHeadingNarrow: obj.FontHeadingNarrow, + FontLink: obj.FontLink, + FontMono: obj.FontMono, + International: obj.International, + LastAccountNumber: obj.LastAccountNumber, + LastModifiedByID: obj.LastModifiedByID, + LastModifiedDate: obj.LastModifiedDate, + LastTaxtypeNumber: obj.LastTaxtypeNumber, + Logo: obj.Logo, + Name: obj.Name, + OwnerID: obj.OwnerID, + Preparer: GetContact(obj.PreparerID, principal), + PreparerID: obj.PreparerID, + PricebookID: obj.PricebookID, + TenantID: obj.TenantID, + UserTechLead: GetContact(obj.UserTechLeadID, principal), + UserTechLeadID: obj.UserTechLeadID, + } +} diff --git a/app/root.go b/app/root.go index 8e6bf11..f348fa8 100644 --- a/app/root.go +++ b/app/root.go @@ -9,6 +9,7 @@ import ( "code.tnxs.net/taxnexus/lib/api/crm/crm_client" "code.tnxs.net/taxnexus/lib/api/geo/geo_client" "code.tnxs.net/taxnexus/lib/api/ops/ops_client" + "code.tnxs.net/taxnexus/lib/api/regs/regs_client" "code.tnxs.net/taxnexus/lib/api/stash/stash_client" "code.tnxs.net/taxnexus/lib/app/logger" httptransport "github.com/go-openapi/runtime/client" @@ -25,6 +26,7 @@ var geoClient = geo_client.Default var crmClient = crm_client.Default var stashClient = stash_client.Default var opsClient = ops_client.Default +var regsClient = regs_client.Default var configured = false var apiUsers map[string]User