From e029966bb44e1f17fe0789e06ec37754409fe1db Mon Sep 17 00:00:00 2001 From: Angel Beltran Date: Sun, 1 Mar 2026 03:36:47 -0700 Subject: [PATCH] mock events saved to db --- database_migrations/000026_mock_events.up.sql | 137 ++++---- .../000027_mock_events_page.down.sql | 9 + .../000027_mock_events_page.up.sql | 23 ++ domains/accounts/accounts.go | 294 +++++++++++++++++ domains/accounts/store_with_context.go | 16 + domains/accounts/sync_groups.go | 8 - server/api/accounts/router.go | 123 ++++++-- styles/index.css | 20 ++ .../simulations/refund-form.html.tmpl | 136 ++++++++ .../simulations/sales-form.html.tmpl | 136 ++++++++ .../simulations/set-inventory-form.html.tmpl | 136 ++++++++ templates/components/button.html.tmpl | 1 + .../{acctID.int64}/simulations.html.tmpl | 297 +++--------------- 13 files changed, 970 insertions(+), 366 deletions(-) create mode 100644 database_migrations/000027_mock_events_page.down.sql create mode 100644 database_migrations/000027_mock_events_page.up.sql create mode 100644 templates/components/accounts/{acctID.int64}/simulations/refund-form.html.tmpl create mode 100644 templates/components/accounts/{acctID.int64}/simulations/sales-form.html.tmpl create mode 100644 templates/components/accounts/{acctID.int64}/simulations/set-inventory-form.html.tmpl diff --git a/database_migrations/000026_mock_events.up.sql b/database_migrations/000026_mock_events.up.sql index 82e26c0..e215738 100644 --- a/database_migrations/000026_mock_events.up.sql +++ b/database_migrations/000026_mock_events.up.sql @@ -1,17 +1,16 @@ BEGIN; --- raw store events +-- raw shop events CREATE TABLE mock.raw_shop_events ( platform TEXT NOT NULL, - store_id TEXT NOT NULL, + shop_id TEXT NOT NULL, event_timestamp TIMESTAMPTZ NOT NULL, event_id TEXT NOT NULL, raw_payload JSONB NOT NULL, - parsed BOOLEAN NOT NULL DEFAULT FALSE, - PRIMARY KEY (platform, store_id, event_id, event_timestamp) + PRIMARY KEY (platform, shop_id, event_id, event_timestamp) ); @@ -19,132 +18,132 @@ CREATE TABLE mock.raw_shop_events ( CREATE TABLE mock.shop_amazon_events ( platform TEXT NOT NULL DEFAULT 'amazon' CHECK (platform = 'amazon'), - store_id TEXT NOT NULL, + shop_id TEXT NOT NULL, event_timestamp TIMESTAMPTZ NOT NULL, event_id TEXT NOT NULL, - PRIMARY KEY (store_id, event_id, event_timestamp), - FOREIGN KEY (platform, store_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events + PRIMARY KEY (shop_id, event_id, event_timestamp), + FOREIGN KEY (platform, shop_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events ); CREATE TABLE mock.shop_big_cartel_events ( platform TEXT NOT NULL DEFAULT 'big_cartel' CHECK (platform = 'big_cartel'), - store_id TEXT NOT NULL, + shop_id TEXT NOT NULL, event_timestamp TIMESTAMPTZ NOT NULL, event_id TEXT NOT NULL, - PRIMARY KEY (store_id, event_id, event_timestamp), - FOREIGN KEY (platform, store_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events + PRIMARY KEY (shop_id, event_id, event_timestamp), + FOREIGN KEY (platform, shop_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events ); CREATE TABLE mock.shop_ebay_events ( platform TEXT NOT NULL DEFAULT 'ebay' CHECK (platform = 'ebay'), - store_id TEXT NOT NULL, + shop_id TEXT NOT NULL, event_timestamp TIMESTAMPTZ NOT NULL, event_id TEXT NOT NULL, - PRIMARY KEY (store_id, event_id, event_timestamp), - FOREIGN KEY (platform, store_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events + PRIMARY KEY (shop_id, event_id, event_timestamp), + FOREIGN KEY (platform, shop_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events ); CREATE TABLE mock.shop_ecwid_events ( platform TEXT NOT NULL DEFAULT 'ecwid' CHECK (platform = 'ecwid'), - store_id TEXT NOT NULL, + shop_id TEXT NOT NULL, event_timestamp TIMESTAMPTZ NOT NULL, event_id TEXT NOT NULL, - PRIMARY KEY (store_id, event_id, event_timestamp), - FOREIGN KEY (platform, store_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events + PRIMARY KEY (shop_id, event_id, event_timestamp), + FOREIGN KEY (platform, shop_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events ); CREATE TABLE mock.shop_etsy_events ( platform TEXT NOT NULL DEFAULT 'etsy' CHECK (platform = 'etsy'), - store_id TEXT NOT NULL, + shop_id TEXT NOT NULL, event_timestamp TIMESTAMPTZ NOT NULL, event_id TEXT NOT NULL, - PRIMARY KEY (store_id, event_id, event_timestamp), - FOREIGN KEY (platform, store_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events + PRIMARY KEY (shop_id, event_id, event_timestamp), + FOREIGN KEY (platform, shop_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events ); CREATE TABLE mock.shop_shopify_events ( platform TEXT NOT NULL DEFAULT 'shopify' CHECK (platform = 'shopify'), - store_id TEXT NOT NULL, + shop_id TEXT NOT NULL, event_timestamp TIMESTAMPTZ NOT NULL, event_id TEXT NOT NULL, - PRIMARY KEY (store_id, event_id, event_timestamp), - FOREIGN KEY (platform, store_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events + PRIMARY KEY (shop_id, event_id, event_timestamp), + FOREIGN KEY (platform, shop_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events ); CREATE TABLE mock.shop_square_online_events ( platform TEXT NOT NULL DEFAULT 'square_online' CHECK (platform = 'square_online'), - store_id TEXT NOT NULL, + shop_id TEXT NOT NULL, event_timestamp TIMESTAMPTZ NOT NULL, event_id TEXT NOT NULL, - PRIMARY KEY (store_id, event_id, event_timestamp), - FOREIGN KEY (platform, store_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events + PRIMARY KEY (shop_id, event_id, event_timestamp), + FOREIGN KEY (platform, shop_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events ); CREATE TABLE mock.shop_squarespace_events ( platform TEXT NOT NULL DEFAULT 'squarespace' CHECK (platform = 'squarespace'), - store_id TEXT NOT NULL, + shop_id TEXT NOT NULL, event_timestamp TIMESTAMPTZ NOT NULL, event_id TEXT NOT NULL, - PRIMARY KEY (store_id, event_id, event_timestamp), - FOREIGN KEY (platform, store_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events + PRIMARY KEY (shop_id, event_id, event_timestamp), + FOREIGN KEY (platform, shop_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events ); CREATE TABLE mock.shop_tiktok_events ( platform TEXT NOT NULL DEFAULT 'tiktok' CHECK (platform = 'tiktok'), - store_id TEXT NOT NULL, + shop_id TEXT NOT NULL, event_timestamp TIMESTAMPTZ NOT NULL, event_id TEXT NOT NULL, - PRIMARY KEY (store_id, event_id, event_timestamp), - FOREIGN KEY (platform, store_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events + PRIMARY KEY (shop_id, event_id, event_timestamp), + FOREIGN KEY (platform, shop_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events ); CREATE TABLE mock.shop_walmart_marketplace_events ( platform TEXT NOT NULL DEFAULT 'walmart_marketplace' CHECK (platform = 'walmart_marketplace'), - store_id TEXT NOT NULL, + shop_id TEXT NOT NULL, event_timestamp TIMESTAMPTZ NOT NULL, event_id TEXT NOT NULL, - PRIMARY KEY (store_id, event_id, event_timestamp), - FOREIGN KEY (platform, store_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events + PRIMARY KEY (shop_id, event_id, event_timestamp), + FOREIGN KEY (platform, shop_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events ); CREATE TABLE mock.shop_wix_events ( platform TEXT NOT NULL DEFAULT 'wix' CHECK (platform = 'wix'), - store_id TEXT NOT NULL, + shop_id TEXT NOT NULL, event_timestamp TIMESTAMPTZ NOT NULL, event_id TEXT NOT NULL, - PRIMARY KEY (store_id, event_id, event_timestamp), - FOREIGN KEY (platform, store_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events + PRIMARY KEY (shop_id, event_id, event_timestamp), + FOREIGN KEY (platform, shop_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events ); CREATE TABLE mock.shop_woo_commerce_events ( platform TEXT NOT NULL DEFAULT 'woo_commerce' CHECK (platform = 'woo_commerce'), - store_id TEXT NOT NULL, + shop_id TEXT NOT NULL, event_timestamp TIMESTAMPTZ NOT NULL, event_id TEXT NOT NULL, - PRIMARY KEY (store_id, event_id, event_timestamp), - FOREIGN KEY (platform, store_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events + PRIMARY KEY (shop_id, event_id, event_timestamp), + FOREIGN KEY (platform, shop_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events ); CREATE TABLE mock.shop_zoho_events ( platform TEXT NOT NULL DEFAULT 'zoho' CHECK (platform = 'zoho'), - store_id TEXT NOT NULL, + shop_id TEXT NOT NULL, event_timestamp TIMESTAMPTZ NOT NULL, event_id TEXT NOT NULL, - PRIMARY KEY (store_id, event_id, event_timestamp), - FOREIGN KEY (platform, store_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events + PRIMARY KEY (shop_id, event_id, event_timestamp), + FOREIGN KEY (platform, shop_id, event_id, event_timestamp) REFERENCES mock.raw_shop_events ); @@ -154,13 +153,13 @@ CREATE OR REPLACE FUNCTION mock.process_raw_amazon_event() RETURNS TRIGGER AS $p BEGIN INSERT INTO mock.shop_amazon_events ( platform, - store_id, + shop_id, event_timestamp, event_id ) SELECT NEW.platform, - NEW.store_id, + NEW.shop_id, NEW.event_timestamp, NEW.event_id; RETURN NULL; @@ -178,13 +177,13 @@ CREATE OR REPLACE FUNCTION mock.process_raw_big_cartel_event() RETURNS TRIGGER A BEGIN INSERT INTO mock.shop_big_cartel_events ( platform, - store_id, + shop_id, event_timestamp, event_id ) SELECT NEW.platform, - NEW.store_id, + NEW.shop_id, NEW.event_timestamp, NEW.event_id; RETURN NULL; @@ -202,13 +201,13 @@ CREATE OR REPLACE FUNCTION mock.process_raw_ebay_event() RETURNS TRIGGER AS $pro BEGIN INSERT INTO mock.shop_ebay_events ( platform, - store_id, + shop_id, event_timestamp, event_id ) SELECT NEW.platform, - NEW.store_id, + NEW.shop_id, NEW.event_timestamp, NEW.event_id; RETURN NULL; @@ -226,13 +225,13 @@ CREATE OR REPLACE FUNCTION mock.process_raw_ecwid_event() RETURNS TRIGGER AS $pr BEGIN INSERT INTO mock.shop_ecwid_events ( platform, - store_id, + shop_id, event_timestamp, event_id ) SELECT NEW.platform, - NEW.store_id, + NEW.shop_id, NEW.event_timestamp, NEW.event_id; RETURN NULL; @@ -250,13 +249,13 @@ CREATE OR REPLACE FUNCTION mock.process_raw_etsy_event() RETURNS TRIGGER AS $pro BEGIN INSERT INTO mock.shop_etsy_events ( platform, - store_id, + shop_id, event_timestamp, event_id ) SELECT NEW.platform, - NEW.store_id, + NEW.shop_id, NEW.event_timestamp, NEW.event_id; RETURN NULL; @@ -274,13 +273,13 @@ CREATE OR REPLACE FUNCTION mock.process_raw_shopify_event() RETURNS TRIGGER AS $ BEGIN INSERT INTO mock.shop_shopify_events ( platform, - store_id, + shop_id, event_timestamp, event_id ) SELECT NEW.platform, - NEW.store_id, + NEW.shop_id, NEW.event_timestamp, NEW.event_id; RETURN NULL; @@ -298,13 +297,13 @@ CREATE OR REPLACE FUNCTION mock.process_raw_square_online_event() RETURNS TRIGGE BEGIN INSERT INTO mock.shop_square_online_events ( platform, - store_id, + shop_id, event_timestamp, event_id ) SELECT NEW.platform, - NEW.store_id, + NEW.shop_id, NEW.event_timestamp, NEW.event_id; RETURN NULL; @@ -322,13 +321,13 @@ CREATE OR REPLACE FUNCTION mock.process_raw_squarespace_event() RETURNS TRIGGER BEGIN INSERT INTO mock.shop_squarespace_events ( platform, - store_id, + shop_id, event_timestamp, event_id ) SELECT NEW.platform, - NEW.store_id, + NEW.shop_id, NEW.event_timestamp, NEW.event_id; RETURN NULL; @@ -346,13 +345,13 @@ CREATE OR REPLACE FUNCTION mock.process_raw_tiktok_event() RETURNS TRIGGER AS $p BEGIN INSERT INTO mock.shop_tiktok_events ( platform, - store_id, + shop_id, event_timestamp, event_id ) SELECT NEW.platform, - NEW.store_id, + NEW.shop_id, NEW.event_timestamp, NEW.event_id; RETURN NULL; @@ -370,13 +369,13 @@ CREATE OR REPLACE FUNCTION mock.process_raw_walmart_marketplace_event() RETURNS BEGIN INSERT INTO mock.shop_walmart_marketplace_events ( platform, - store_id, + shop_id, event_timestamp, event_id ) SELECT NEW.platform, - NEW.store_id, + NEW.shop_id, NEW.event_timestamp, NEW.event_id; RETURN NULL; @@ -394,13 +393,13 @@ CREATE OR REPLACE FUNCTION mock.process_raw_wix_event() RETURNS TRIGGER AS $proc BEGIN INSERT INTO mock.shop_wix_events ( platform, - store_id, + shop_id, event_timestamp, event_id ) SELECT NEW.platform, - NEW.store_id, + NEW.shop_id, NEW.event_timestamp, NEW.event_id; RETURN NULL; @@ -418,13 +417,13 @@ CREATE OR REPLACE FUNCTION mock.process_raw_woo_commerce_event() RETURNS TRIGGER BEGIN INSERT INTO mock.shop_woo_commerce_events ( platform, - store_id, + shop_id, event_timestamp, event_id ) SELECT NEW.platform, - NEW.store_id, + NEW.shop_id, NEW.event_timestamp, NEW.event_id; RETURN NULL; @@ -442,13 +441,13 @@ CREATE OR REPLACE FUNCTION mock.process_raw_zoho_event() RETURNS TRIGGER AS $pro BEGIN INSERT INTO mock.shop_zoho_events ( platform, - store_id, + shop_id, event_timestamp, event_id ) SELECT NEW.platform, - NEW.store_id, + NEW.shop_id, NEW.event_timestamp, NEW.event_id; RETURN NULL; diff --git a/database_migrations/000027_mock_events_page.down.sql b/database_migrations/000027_mock_events_page.down.sql new file mode 100644 index 0000000..b74add2 --- /dev/null +++ b/database_migrations/000027_mock_events_page.down.sql @@ -0,0 +1,9 @@ +BEGIN; + + +DROP TABLE mock.sale_form_shop_selection; +DROP TABLE mock.refund_form_shop_selection; +DROP TABLE mock.count_form_shop_selection; + + +COMMIT; diff --git a/database_migrations/000027_mock_events_page.up.sql b/database_migrations/000027_mock_events_page.up.sql new file mode 100644 index 0000000..dded0af --- /dev/null +++ b/database_migrations/000027_mock_events_page.up.sql @@ -0,0 +1,23 @@ +BEGIN; + + +CREATE TABLE mock.sale_form_shop_selection ( + account_id INTEGER PRIMARY KEY, + platform PLATFORM NOT NULL, + shop_id TEXT NOT NULL +); + +CREATE TABLE mock.refund_form_shop_selection ( + account_id INTEGER PRIMARY KEY, + platform PLATFORM NOT NULL, + shop_id TEXT NOT NULL +); + +CREATE TABLE mock.count_form_shop_selection ( + account_id INTEGER PRIMARY KEY, + platform PLATFORM NOT NULL, + shop_id TEXT NOT NULL +); + + +COMMIT; diff --git a/domains/accounts/accounts.go b/domains/accounts/accounts.go index 63b2a7b..09ee8d0 100644 --- a/domains/accounts/accounts.go +++ b/domains/accounts/accounts.go @@ -5,11 +5,13 @@ package accounts import ( "context" + "encoding/json" "errors" "fmt" "slices" "strings" + "github.com/google/uuid" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgxpool" @@ -1461,6 +1463,290 @@ func (db *Store) DeleteListingInListingInMockSyncGroupBeingEdited(ctx context.Co return nil } +// if err := s.accts.SetShopInMockSaleForm(c, acctID, platform, shopID); err != nil { + +func (db *Store) SetShopInMockSaleForm(ctx context.Context, acctID int64, platform Platform, shopID string) error { + _, err := db.db.Exec( + ctx, + ` + INSERT INTO + mock.sale_form_shop_selection ( + account_id, + platform, + shop_id + ) + VALUES ( + @account_id, + @platform, + @shop_id + ) + ON CONFLICT (account_id) DO UPDATE + SET platform = EXCLUDED.platform, + shop_id = EXCLUDED.shop_id + `, + pgx.NamedArgs{ + "account_id": acctID, + "platform": platform, + "shop_id": shopID, + }, + ) + if err != nil { + return fmt.Errorf("failed to perform query: %w", err) + } + + return nil +} + +func (db *Store) SetShopInMockRefundForm(ctx context.Context, acctID int64, platform Platform, shopID string) error { + _, err := db.db.Exec( + ctx, + ` + INSERT INTO + mock.refund_form_shop_selection ( + account_id, + platform, + shop_id + ) + VALUES ( + @account_id, + @platform, + @shop_id + ) + ON CONFLICT (account_id) DO UPDATE + SET platform = EXCLUDED.platform, + shop_id = EXCLUDED.shop_id + `, + pgx.NamedArgs{ + "account_id": acctID, + "platform": platform, + "shop_id": shopID, + }, + ) + if err != nil { + return fmt.Errorf("failed to perform query: %w", err) + } + + return nil +} + +func (db *Store) SetShopInMockCountForm(ctx context.Context, acctID int64, platform Platform, shopID string) error { + _, err := db.db.Exec( + ctx, + ` + INSERT INTO + mock.count_form_shop_selection ( + account_id, + platform, + shop_id + ) + VALUES ( + @account_id, + @platform, + @shop_id + ) + ON CONFLICT (account_id) DO UPDATE + SET platform = EXCLUDED.platform, + shop_id = EXCLUDED.shop_id + `, + pgx.NamedArgs{ + "account_id": acctID, + "platform": platform, + "shop_id": shopID, + }, + ) + if err != nil { + return fmt.Errorf("failed to perform query: %w", err) + } + + return nil +} + +type MockEventFormValues struct { + SaleShopID string + SalePlatform Platform + RefundShopID string + RefundPlatform Platform + CountShopID string + CountPlatform Platform +} + +func (db *Store) GetMockEventFormValues(ctx context.Context, acctID int64) (*MockEventFormValues, error) { + rows, err := db.db.Query( + ctx, + ` + SELECT + sf.platform AS sale_platform, + sf.shop_id AS sale_shop_id, + rf.platform AS refund_platform, + rf.shop_id AS refund_shop_id, + cf.platform AS count_platform, + cf.shop_id AS count_shop_id + FROM + mock.sale_form_shop_selection AS sf + FULL OUTER JOIN + mock.refund_form_shop_selection AS rf + USING + (account_id) + FULL OUTER JOIN + mock.count_form_shop_selection AS cf + USING + (account_id) + WHERE + sf.account_id = @account_id + `, + pgx.NamedArgs{ + "account_id": acctID, + }, + ) + if err != nil { + return nil, fmt.Errorf("failed to perform query: %w", err) + } + + v, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByNameLax[struct { + Sale_shop_id pgtype.Text + Sale_platform *Platform + Refund_shop_id pgtype.Text + Refund_platform *Platform + Count_shop_id pgtype.Text + Count_platform *Platform + }]) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return &MockEventFormValues{}, nil + } + return nil, fmt.Errorf("failed to scan rows: %w", err) + } + + return &MockEventFormValues{ + SaleShopID: v.Sale_shop_id.String, + SalePlatform: deref(v.Sale_platform), + RefundShopID: v.Refund_shop_id.String, + RefundPlatform: deref(v.Refund_platform), + CountShopID: v.Count_shop_id.String, + CountPlatform: deref(v.Count_platform), + }, nil +} + +func (db *Store) SaveNewMockSale(ctx context.Context, acctID int64, platform Platform, shopID, listingID string, count int) (uuid.UUID, error) { + eventID := uuid.New() + + _, err := db.db.Exec( + ctx, + ` + INSERT INTO + mock.raw_shop_events ( + platform, + shop_id, + event_timestamp, + event_id, + raw_payload + ) + VALUES ( + @platform, + @shop_id, + NOW(), + @event_id, + @raw_payload + ) + `, + pgx.NamedArgs{ + "platform": platform, + "shop_id": shopID, + "event_id": eventID, + "raw_payload": json.RawMessage(fmt.Sprintf(`{ + "type": "sale", + "listingID": %q, + "count": %d +}`, listingID, count)), + }, + ) + if err != nil { + return uuid.Nil, fmt.Errorf("failed to perform query: %w", err) + } + + return eventID, nil +} + +func (db *Store) SaveNewMockRefund(ctx context.Context, acctID int64, platform Platform, shopID, listingID string, count int) (uuid.UUID, error) { + eventID := uuid.New() + + _, err := db.db.Exec( + ctx, + ` + INSERT INTO + mock.raw_shop_events ( + platform, + shop_id, + event_timestamp, + event_id, + raw_payload + ) + VALUES ( + @platform, + @shop_id, + NOW(), + @event_id, + @raw_payload + ) + `, + pgx.NamedArgs{ + "platform": platform, + "shop_id": shopID, + "event_id": eventID, + "raw_payload": json.RawMessage(fmt.Sprintf(`{ + "type": "refund", + "listingID": %q, + "count": %d +}`, listingID, count)), + }, + ) + if err != nil { + return uuid.Nil, fmt.Errorf("failed to perform query: %w", err) + } + + return eventID, nil +} + +func (db *Store) SaveNewMockInventoryReset(ctx context.Context, acctID int64, platform Platform, shopID, listingID string, count int) (uuid.UUID, error) { + eventID := uuid.New() + + _, err := db.db.Exec( + ctx, + ` + INSERT INTO + mock.raw_shop_events ( + platform, + shop_id, + event_timestamp, + event_id, + raw_payload + ) + VALUES ( + @platform, + @shop_id, + NOW(), + @event_id, + @raw_payload + ) + `, + pgx.NamedArgs{ + "platform": platform, + "shop_id": shopID, + "event_id": eventID, + "raw_payload": json.RawMessage(fmt.Sprintf(`{ + "type": "inventory-reset", + "listingID": %q, + "count": %d +}`, listingID, count)), + }, + ) + if err != nil { + return uuid.Nil, fmt.Errorf("failed to perform query: %w", err) + } + + return eventID, nil +} + // additional context func (db *Store) GetAccountPointerByUserID(ctx context.Context, userID string) (*Account, error) { @@ -1481,3 +1767,11 @@ func (db *Store) beginReadonlyTxn(ctx context.Context, cb func(pgx.Tx) error) er func (db *Store) beginTxn(ctx context.Context, cb func(pgx.Tx) error) error { return pgx.BeginFunc(ctx, db.db, cb) } + +func deref[T any](ptr *T) T { + if ptr != nil { + return *ptr + } + var zero T + return zero +} diff --git a/domains/accounts/store_with_context.go b/domains/accounts/store_with_context.go index 2c4fe0f..7c190c0 100644 --- a/domains/accounts/store_with_context.go +++ b/domains/accounts/store_with_context.go @@ -105,6 +105,22 @@ func (v_ctx *StoreWithContext) DeleteListingInListingInMockSyncGroupBeingEdited( return v_ctx.Store.DeleteListingInListingInMockSyncGroupBeingEdited(v_ctx.ctx, acctID, orderIndex) } +func (v_ctx *StoreWithContext) SetShopInMockSaleForm(acctID int64, platform Platform, shopID string) error { + return v_ctx.Store.SetShopInMockSaleForm(v_ctx.ctx, acctID, platform, shopID) +} + +func (v_ctx *StoreWithContext) SetShopInMockRefundForm(acctID int64, platform Platform, shopID string) error { + return v_ctx.Store.SetShopInMockRefundForm(v_ctx.ctx, acctID, platform, shopID) +} + +func (v_ctx *StoreWithContext) SetShopInMockCountForm(acctID int64, platform Platform, shopID string) error { + return v_ctx.Store.SetShopInMockCountForm(v_ctx.ctx, acctID, platform, shopID) +} + +func (v_ctx *StoreWithContext) GetMockEventFormValues(acctID int64) (*MockEventFormValues, error) { + return v_ctx.Store.GetMockEventFormValues(v_ctx.ctx, acctID) +} + func (v_ctx *StoreWithContext) GetAccountPointerByUserID(userID string) (*Account, error) { return v_ctx.Store.GetAccountPointerByUserID(v_ctx.ctx, userID) } diff --git a/domains/accounts/sync_groups.go b/domains/accounts/sync_groups.go index dc9abe9..f638829 100644 --- a/domains/accounts/sync_groups.go +++ b/domains/accounts/sync_groups.go @@ -1235,11 +1235,3 @@ func (db *Store) listMockSyncGroupListings(ctx context.Context, tx pgx.Tx, acctI return listings, nil } - -func deref[T any](ptr *T) T { - if ptr == nil { - var zero T - return zero - } - return *ptr -} diff --git a/server/api/accounts/router.go b/server/api/accounts/router.go index a0fa731..2579e36 100644 --- a/server/api/accounts/router.go +++ b/server/api/accounts/router.go @@ -79,10 +79,13 @@ func Routes( mockSyncGroupBeingEdited.PUT("/listings/:orderIndex/listing", response.Handler(as.setListingInListingInMockSyncGroupBeingEdited)) mockSyncGroupBeingEdited.DELETE("/listings/:orderIndex", response.Handler(as.deleteListingInListingInMockSyncGroupBeingEdited)) - simulations := r.Group("/:acctID/simulations") - simulations.POST("/sale", response.Handler(as.postNewSale)) - simulations.POST("/refund", response.Handler(as.postNewRefund)) - simulations.PUT("/shops/:shopID/listings/:listingID/count", response.Handler(as.setListingCount)) + simulations := r.Group("/:acctID/simulations", pub.Publish("/:acctID/simulations")) + simulations.PUT("/sale/form/shop", response.Handler(as.setShopInMockSaleForm)) + simulations.POST("/sale", response.Handler(as.postNewMockSale)) + simulations.PUT("/refund/form/shop", response.Handler(as.setShopInMockRefundForm)) + simulations.POST("/refund", response.Handler(as.postNewMockRefund)) + simulations.PUT("/count/form/shop", response.Handler(as.setShopInMockCountForm)) + simulations.PUT("/shops/:shopID/listings/:listingID/count", response.Handler(as.setMockListingCount)) } // POST / @@ -741,80 +744,146 @@ func (s *accountSubrouter) deleteListingInListingInMockSyncGroupBeingEdited(c *g return response.StatusOK(), nil } -// POST /:acctID/simulations/sale -func (s *accountSubrouter) postNewSale(c *gin.Context) (response.Response, error) { +// PUT /:acctID/simulations/sale/form/shop +func (s *accountSubrouter) setShopInMockSaleForm(c *gin.Context) (response.Response, error) { acctID := auth.GetIdentity(c).Account.AccountID var ( + platform accounts.Platform + shopID string + ) + + if err := param.Form("platform", param.Platform(&platform)). + Form("shop-id", param.Text(&shopID)). + Unmarshal(c); err != nil { + return nil, err + } + + if err := s.accts.SetShopInMockSaleForm(c, acctID, platform, shopID); err != nil { + return nil, fmt.Errorf("failed to set shop in mock sale form: %w", err) + } + + return response.StatusOK(), nil +} + +// POST /:acctID/simulations/sale +func (s *accountSubrouter) postNewMockSale(c *gin.Context) (response.Response, error) { + acctID := auth.GetIdentity(c).Account.AccountID + + var ( + platform accounts.Platform shopID string listingID string count int ) - if err := param.Form("shop-id", param.Text(&shopID)). + if err := param.Form("platform", param.Platform(&platform)). + Form("shop-id", param.Text(&shopID)). Form("listing-id", param.Text(&listingID)). Form("count", param.Int(&count)). Unmarshal(c); err != nil { return nil, err } - s.log.Debugf("sale posted:") - s.log.Debugf(" account: %d", acctID) - s.log.Debugf(" shop: %s", shopID) - s.log.Debugf(" listing: %s", listingID) - s.log.Debugf(" count: %d", count) + if _, err := s.accts.SaveNewMockSale(c, acctID, platform, shopID, listingID, count); err != nil { + return nil, fmt.Errorf("failed to save new mock sale: %w", err) + } return response.StatusCreated(), nil } +// PUT /:acctID/simulations/refund/form/shop +func (s *accountSubrouter) setShopInMockRefundForm(c *gin.Context) (response.Response, error) { + acctID := auth.GetIdentity(c).Account.AccountID + + var ( + platform accounts.Platform + shopID string + ) + + if err := param.Form("platform", param.Platform(&platform)). + Form("shop-id", param.Text(&shopID)). + Unmarshal(c); err != nil { + return nil, err + } + + if err := s.accts.SetShopInMockRefundForm(c, acctID, platform, shopID); err != nil { + return nil, fmt.Errorf("failed to set shop in mock refund form: %w", err) + } + + return response.StatusOK(), nil +} + // POST /:acctID/simulations/refund -func (s *accountSubrouter) postNewRefund(c *gin.Context) (response.Response, error) { +func (s *accountSubrouter) postNewMockRefund(c *gin.Context) (response.Response, error) { acctID := auth.GetIdentity(c).Account.AccountID var ( + platform accounts.Platform shopID string listingID string count int ) - if err := param.Form("shop-id", param.Text(&shopID)). + if err := param.Form("platform", param.Platform(&platform)). + Form("shop-id", param.Text(&shopID)). Form("listing-id", param.Text(&listingID)). Form("count", param.Int(&count)). Unmarshal(c); err != nil { return nil, err } - s.log.Debugf("refund posted:") - s.log.Debugf(" account: %d", acctID) - s.log.Debugf(" shop: %s", shopID) - s.log.Debugf(" listing: %s", listingID) - s.log.Debugf(" count: %d", count) + if _, err := s.accts.SaveNewMockRefund(c, acctID, platform, shopID, listingID, count); err != nil { + return nil, fmt.Errorf("failed to save new mock refund: %w", err) + } return response.StatusCreated(), nil } -// PUT /:acctID/simulations/shops/:shopID/listings/:listingID/count -func (s *accountSubrouter) setListingCount(c *gin.Context) (response.Response, error) { +// PUT /:acctID/simulations/count/form/shop +func (s *accountSubrouter) setShopInMockCountForm(c *gin.Context) (response.Response, error) { acctID := auth.GetIdentity(c).Account.AccountID var ( + platform accounts.Platform + shopID string + ) + + if err := param.Form("platform", param.Platform(&platform)). + Form("shop-id", param.Text(&shopID)). + Unmarshal(c); err != nil { + return nil, err + } + + if err := s.accts.SetShopInMockCountForm(c, acctID, platform, shopID); err != nil { + return nil, fmt.Errorf("failed to set shop in mock count form: %w", err) + } + + return response.StatusOK(), nil +} + +// PUT /:acctID/simulations/shops/:shopID/listings/:listingID/count +func (s *accountSubrouter) setMockListingCount(c *gin.Context) (response.Response, error) { + acctID := auth.GetIdentity(c).Account.AccountID + + var ( + platform accounts.Platform shopID string listingID string count int ) - if err := param.Path("shopID", param.Text(&shopID)). + if err := param.Form("platform", param.Platform(&platform)). + Path("shopID", param.Text(&shopID)). Path("listingID", param.Text(&listingID)). Form("count", param.Int(&count)). Unmarshal(c); err != nil { return nil, err } - s.log.Debugf("listing inventory set:") - s.log.Debugf(" account: %d", acctID) - s.log.Debugf(" shop: %s", shopID) - s.log.Debugf(" listing: %s", listingID) - s.log.Debugf(" count: %d", count) + if _, err := s.accts.SaveNewMockInventoryReset(c, acctID, platform, shopID, listingID, count); err != nil { + return nil, fmt.Errorf("failed to save new mock inventory reset: %w", err) + } return response.StatusOK(), nil } diff --git a/styles/index.css b/styles/index.css index fd63b68..ca1e853 100644 --- a/styles/index.css +++ b/styles/index.css @@ -906,6 +906,26 @@ } } } + .active\:bg-accent { + &:active { + background-color: var(--accent); + } + } + .active\:bg-accent-secondary { + &:active { + background-color: var(--accent-secondary); + } + } + .active\:bg-muted { + &:active { + background-color: var(--muted); + } + } + .active\:bg-secondary { + &:active { + background-color: var(--secondary); + } + } .disabled\:cursor-not-allowed { &:disabled { cursor: not-allowed; diff --git a/templates/components/accounts/{acctID.int64}/simulations/refund-form.html.tmpl b/templates/components/accounts/{acctID.int64}/simulations/refund-form.html.tmpl new file mode 100644 index 0000000..f3079a7 --- /dev/null +++ b/templates/components/accounts/{acctID.int64}/simulations/refund-form.html.tmpl @@ -0,0 +1,136 @@ +{{/* [ .Shops, .SelectedPlatform, .SelectedShopID, .Listings ] */}} + +{{- $acctID := .Identity.Account.AccountID -}} +{{- $shops := .Shops }} +{{- if not $shops }} + {{- $shops = .Accounts.GetMockShops $acctID -}} +{{- end }} +{{- $selectedPlatform := .SelectedPlatform }} +{{- $selectedShopID := .SelectedShopID }} +{{- if not $selectedPlatform | or (not $selectedShopID) }} + {{- $formSelections := .Accounts.GetMockEventFormValues $acctID }} + {{- $selectedPlatform = $formSelections.RefundPlatform }} + {{- $selectedShopID = $formSelections.RefundShopID }} +{{- end }} +{{- $listings := .Listings }} +{{- if $selectedShopID }} + {{ $listings = .Accounts.GetMockListingsForShop $acctID $selectedPlatform $selectedShopID }} +{{- end }} + + + +{{/* REFUNDS */}} +{{- define "refund-accordion-header" }} +

+ Refund +

+{{ end }} + +{{- define "refund-accordion-body" }} + {{ $acctID := .Identity.Account.AccountID }} + {{ $selectedPlatform := .SelectedPlatform }} + {{ $selectedShopID := .SelectedShopID }} + {{ $listings := .Listings }} + + {{/* form updater*/}} + + +
+ + + + + + +
+ {{ component "button" + "Text" "Submit" + "Background" true + "Class" "m-0" + }} +
+
+{{ end }} + +{{ component "accordion" + "Name" "simulate" + "Shops" $shops + "SelectedPlatform" $selectedPlatform + "SelectedShopID" $selectedShopID + "Listings" $listings + "Class" ` + mx-[1em] + mb-[1em] + ` + "#accordion-header" "refund-accordion-header" + "#accordion-body" "refund-accordion-body" +}} diff --git a/templates/components/accounts/{acctID.int64}/simulations/sales-form.html.tmpl b/templates/components/accounts/{acctID.int64}/simulations/sales-form.html.tmpl new file mode 100644 index 0000000..ceca5d8 --- /dev/null +++ b/templates/components/accounts/{acctID.int64}/simulations/sales-form.html.tmpl @@ -0,0 +1,136 @@ +{{/* [ .Shops, .SelectedPlatform, .SelectedShopID, .Listings ] */}} + +{{- $acctID := .Identity.Account.AccountID -}} +{{- $shops := .Shops }} +{{- if not $shops }} + {{- $shops = .Accounts.GetMockShops $acctID -}} +{{- end }} +{{- $selectedPlatform := .SelectedPlatform }} +{{- $selectedShopID := .SelectedShopID }} +{{- if not $selectedPlatform | or (not $selectedShopID) }} + {{- $formSelections := .Accounts.GetMockEventFormValues $acctID }} + {{- $selectedPlatform = $formSelections.SalePlatform }} + {{- $selectedShopID = $formSelections.SaleShopID }} +{{- end }} +{{- $listings := .Listings }} +{{- if $selectedShopID }} + {{ $listings = .Accounts.GetMockListingsForShop $acctID $selectedPlatform $selectedShopID }} +{{- end }} + + + +{{/* SALES */}} +{{- define "sale-accordion-header" }} +

+ Sale +

+{{ end }} + +{{- define "sale-accordion-body" }} + {{ $acctID := .Identity.Account.AccountID }} + {{ $selectedPlatform := .SelectedPlatform }} + {{ $selectedShopID := .SelectedShopID }} + {{ $listings := .Listings }} + + {{/* form updater*/}} + + +
+ + + + + + +
+ {{ component "button" + "Text" "Submit" + "Background" true + "Class" "m-0" + }} +
+
+{{ end }} + +{{ component "accordion" + "Name" "simulate" + "Shops" $shops + "SelectedPlatform" $selectedPlatform + "SelectedShopID" $selectedShopID + "Listings" $listings + "Class" ` + mx-[1em] + mb-[1em] + ` + "#accordion-header" "sale-accordion-header" + "#accordion-body" "sale-accordion-body" +}} diff --git a/templates/components/accounts/{acctID.int64}/simulations/set-inventory-form.html.tmpl b/templates/components/accounts/{acctID.int64}/simulations/set-inventory-form.html.tmpl new file mode 100644 index 0000000..160e35f --- /dev/null +++ b/templates/components/accounts/{acctID.int64}/simulations/set-inventory-form.html.tmpl @@ -0,0 +1,136 @@ +{{/* [ .Shops, .SelectedPlatform, .SelectedShopID, .Listings ] */}} + +{{- $acctID := .Identity.Account.AccountID -}} +{{- $shops := .Shops }} +{{- if not $shops }} + {{- $shops = .Accounts.GetMockShops $acctID -}} +{{- end }} +{{- $selectedPlatform := .SelectedPlatform }} +{{- $selectedShopID := .SelectedShopID }} +{{- if not $selectedPlatform | or (not $selectedShopID) }} + {{- $formSelections := .Accounts.GetMockEventFormValues $acctID }} + {{- $selectedPlatform = $formSelections.CountPlatform }} + {{- $selectedShopID = $formSelections.CountShopID }} +{{- end }} +{{- $listings := .Listings }} +{{- if $selectedShopID }} + {{ $listings = .Accounts.GetMockListingsForShop $acctID $selectedPlatform $selectedShopID }} +{{- end }} + + + +{{/* SET INVENTORY */}} +{{- define "set-inventory-accordion-header" }} +

+ Set Inventory +

+{{ end }} + +{{- define "set-inventory-accordion-body" }} + {{ $acctID := .Identity.Account.AccountID }} + {{ $selectedPlatform := .SelectedPlatform }} + {{ $selectedShopID := .SelectedShopID }} + {{ $listings := .Listings }} + + {{/* form updater*/}} + + +
+ + + + + + +
+ {{ component "button" + "Text" "Submit" + "Background" true + "Class" "m-0" + }} +
+
+{{ end }} + +{{ component "accordion" + "Name" "simulate" + "Shops" $shops + "SelectedPlatform" $selectedPlatform + "SelectedShopID" $selectedShopID + "Listings" $listings + "Class" ` + mx-[1em] + mb-[1em] + ` + "#accordion-header" "set-inventory-accordion-header" + "#accordion-body" "set-inventory-accordion-body" +}} diff --git a/templates/components/button.html.tmpl b/templates/components/button.html.tmpl index 013b19d..c8d746f 100644 --- a/templates/components/button.html.tmpl +++ b/templates/components/button.html.tmpl @@ -11,6 +11,7 @@ cursor-pointer hover:underline hover:bg-accent + active:bg-accent-secondary disabled:bg-accent-secondary disabled:cursor-not-allowed disabled:no-underline diff --git a/templates/pages/accounts/{acctID.int64}/simulations.html.tmpl b/templates/pages/accounts/{acctID.int64}/simulations.html.tmpl index 671f6b2..618d6ea 100644 --- a/templates/pages/accounts/{acctID.int64}/simulations.html.tmpl +++ b/templates/pages/accounts/{acctID.int64}/simulations.html.tmpl @@ -1,275 +1,48 @@ -

- Simulations +{{- $acctID := .Identity.Account.AccountID -}} +{{- $shops := .Accounts.GetMockShops $acctID -}} +{{- $formSelections := .Accounts.GetMockEventFormValues $acctID -}} + +{{- $saleShopListings := "" }} +{{- if $formSelections.SaleShopID }} + {{ $saleShopListings = .Accounts.GetMockListingsForShop $acctID $formSelections.SalePlatform $formSelections.SaleShopID }} +{{- end }} +{{- $refundShopListings := "" }} +{{- if $formSelections.RefundShopID }} + {{ $refundShopListings = .Accounts.GetMockListingsForShop $acctID $formSelections.SalePlatform $formSelections.RefundShopID }} +{{- end }} +{{- $setInventoryShopListings := "" }} +{{- if $formSelections.CountShopID }} + {{ $setInventoryShopListings = .Accounts.GetMockListingsForShop $acctID $formSelections.SalePlatform $formSelections.CountShopID }} +{{- end }} + + +

+ Simulate

{{/* SALES */}} -{{- define "sale-accordion-header" }} -

- Sale -

-{{ end }} - -{{- define "sale-accordion-body" }} - {{ $acctID := .Identity.Account.AccountID }} -
- - - - - - -
- {{ component "button" - "Text" "Submit" - "Background" true - "Class" "m-0" - }} -
-
-{{ end }} - -{{ component "accordion" - "Name" "simulate" - "Open" true - "Class" ` - mx-[1em] - mb-[1em] - ` - "#accordion-header" "sale-accordion-header" - "#accordion-body" "sale-accordion-body" +{{ component (printf "/accounts/%d/simulations/sales-form" $acctID) + "Shops" $shops + "SelectedPlatform" $formSelections.SalePlatform + "SelectedShopID" $formSelections.SaleShopID + "Listings" $saleShopListings }} {{/* REFUNDS */}} -{{- define "refund-accordion-header" }} -

- Refund -

-{{ end }} - -{{- define "refund-accordion-body" }} - {{ $acctID := .Identity.Account.AccountID }} -
- - - - - - -
- {{ component "button" - "Text" "Submit" - "Background" true - "Class" "m-0" - }} -
-
-{{ end }} - -{{ component "accordion" - "Name" "simulate" - "Class" ` - mx-[1em] - mb-[1em] - ` - "#accordion-header" "refund-accordion-header" - "#accordion-body" "refund-accordion-body" +{{ component (printf "/accounts/%d/simulations/refund-form" $acctID) + "Shops" $shops + "SelectedPlatform" $formSelections.RefundPlatform + "SelectedShopID" $formSelections.RefundShopID + "Listings" $refundShopListings }} {{/* SET INVENTORY */}} -{{- define "set-inventory-accordion-header" }} -

- Set Inventory -

-{{ end }} - -{{- define "set-inventory-accordion-body" }} - {{ $acctID := .Identity.Account.AccountID }} -
- - - - - - -
- {{ component "button" - "Text" "Submit" - "Background" true - "Class" "m-0" - }} -
-
-{{ end }} - -{{ component "accordion" - "Name" "simulate" - "Class" ` - mx-[1em] - mb-[1em] - ` - "#accordion-header" "set-inventory-accordion-header" - "#accordion-body" "set-inventory-accordion-body" +{{ component (printf "/accounts/%d/simulations/set-inventory-form" $acctID) + "Shops" $shops + "SelectedPlatform" $formSelections.CountPlatform + "SelectedShopID" $formSelections.CountShopID + "Listings" $setInventoryShopListings }}