diff --git a/apps/simplex-store-service/src/StoreService/Store/Postgres/Migrations.hs b/apps/simplex-store-service/src/StoreService/Store/Postgres/Migrations.hs index 9e440f4f06..a635f59a60 100644 --- a/apps/simplex-store-service/src/StoreService/Store/Postgres/Migrations.hs +++ b/apps/simplex-store-service/src/StoreService/Store/Postgres/Migrations.hs @@ -291,6 +291,7 @@ CREATE INDEX @idx_name_transactions_status ON @name_transactions(status, registr |] -- A table another table's foreign key references cannot be dropped, so reserved_by goes first. +-- The name orders' invoices go with them, except those with a payment, which stay for the accounts. down_m20261010_names :: Text down_m20261010_names = withPrefix @@ -306,6 +307,10 @@ DROP INDEX @idx_name_record_edits_body_hash; DROP INDEX @idx_name_record_edits_owner_nonce; DROP TABLE @name_record_edits; +DELETE FROM @invoices WHERE invoice_id IN ( + SELECT ni.invoice_id FROM @name_invoices ni + WHERE NOT EXISTS (SELECT 1 FROM @payments p WHERE p.invoice_id = ni.invoice_id) +); DROP INDEX @idx_name_invoices_provider_ref; DROP INDEX @idx_name_invoices_registration; DROP TABLE @name_invoices; diff --git a/apps/simplex-store-service/src/StoreService/Store/SQLite/Migrations.hs b/apps/simplex-store-service/src/StoreService/Store/SQLite/Migrations.hs index a86cda9c65..187947c32d 100644 --- a/apps/simplex-store-service/src/StoreService/Store/SQLite/Migrations.hs +++ b/apps/simplex-store-service/src/StoreService/Store/SQLite/Migrations.hs @@ -293,6 +293,7 @@ CREATE INDEX @idx_name_transactions_status ON @name_transactions(status, registr -- SQLite refuses to drop a column in a foreign key, and dropping a table deletes its rows first, -- so the codes' references to registrations are cleared before the registrations go. +-- The name orders' invoices go with them, except those with a payment, which stay for the accounts. down_m20261010_names :: Query down_m20261010_names = withPrefix @@ -308,6 +309,10 @@ DROP INDEX @idx_name_record_edits_body_hash; DROP INDEX @idx_name_record_edits_owner_nonce; DROP TABLE @name_record_edits; +DELETE FROM @invoices WHERE invoice_id IN ( + SELECT ni.invoice_id FROM @name_invoices ni + WHERE NOT EXISTS (SELECT 1 FROM @payments p WHERE p.invoice_id = ni.invoice_id) +); DROP INDEX @idx_name_invoices_provider_ref; DROP INDEX @idx_name_invoices_registration; DROP TABLE @name_invoices; diff --git a/tests/Bots/StoreService/NamesStoreTests.hs b/tests/Bots/StoreService/NamesStoreTests.hs index ad66c6abff..8105d316a7 100644 --- a/tests/Bots/StoreService/NamesStoreTests.hs +++ b/tests/Bots/StoreService/NamesStoreTests.hs @@ -41,7 +41,7 @@ namesStoreTests :: Spec namesStoreTests = describe "StoreService names: store" $ do describe "migration" $ do it "creates the names tables with the planned columns" testNamesColumns - it "rolls back and re-applies only the names migration, with rows in it, leaving the badge tables as they were" testNamesDownUp + it "rolls back and re-applies only the names migration, with rows in it, leaving the badge tables and paid invoices as they were" testNamesDownUp describe "order hash" $ do it "is equal for the same order fields, and differs when any one field differs" testOrderHashFields it "keeps field boundaries, so moving a byte between two fields changes it" testOrderHashBoundaries @@ -188,8 +188,11 @@ testNamesDownUp = withServiceStore $ \st -> do code <- issue st 1 usable placeCode st "r1" ownerA (order "alicebakery" 1) code `shouldReturn` Right () placePaid st "r2" ownerB (order "bobsbakery" 2) (at 60) `shouldReturn` Right () + placePaid st "r3" ownerB (order "carolsbakery" 3) (at 60) `shouldReturn` Right () + withTransaction st $ \db -> insertPayment db "inv-r3" runMigrations st $ MTRDown (mapMaybe toDownMigration names) mapM (columnsOf st) namesTables `shouldReturn` map (const []) namesTables + mapM (invoiceCount st) ["inv-r2", "inv-r3"] `shouldReturn` [0, 1] badgeColumns `shouldReturn` badgeBefore runMigrations st $ MTRUp names mapM (fmap null . columnsOf st) namesTables `shouldReturn` map (const False) namesTables @@ -580,11 +583,7 @@ testUnpaidCleanup = withServiceStore $ \st -> do placePaid st "funded" ownerA (order "bobsbakery" 2) (at 60) `shouldReturn` Right () placePaid st "queued" ownerA (order "carolsbakery" 3) (at 60) `shouldReturn` Right () placePaid st "open" ownerA (order "davesbakery" 4) (at 120) `shouldReturn` Right () - withTransaction st $ \db -> - DB.execute - db - "INSERT INTO sx_badge_service_payments (payment_id, invoice_id, provider, status, created_at, updated_at) VALUES (?,?,?,?,?,?)" - ("inv-funded" :: Text, "inv-funded" :: Text, "crypto" :: Text, "pending" :: Text, t0, t0) + withTransaction st $ \db -> insertPayment db "inv-funded" r <- reg st "queued" void $ write st r {nrPhase = PQueued} candidates <- withTransaction st $ \db -> unpaidCleanupCandidates db (at 61) @@ -595,6 +594,13 @@ testUnpaidCleanup = withServiceStore $ \st -> do invoiceCount st "inv-funded" `shouldReturn` 1 nrPhase <$> reg st "funded" `shouldReturn` PUnpaid +insertPayment :: DB.Connection -> Text -> IO () +insertPayment db invId = + DB.execute + db + "INSERT INTO sx_badge_service_payments (payment_id, invoice_id, provider, status, created_at, updated_at) VALUES (?,?,?,?,?,?)" + (invId, invId, "crypto" :: Text, "pending" :: Text, t0, t0) + invoiceCount :: DBStore -> Text -> IO Int invoiceCount st invId = withTransaction st $ \db -> DB.query db "SELECT COUNT(*) FROM sx_badge_service_invoices WHERE invoice_id = ?" (Only invId) >>= \case