diff --git a/api/prisma/schema.prisma b/api/prisma/schema.prisma index a368cb8..f8d03ec 100644 --- a/api/prisma/schema.prisma +++ b/api/prisma/schema.prisma @@ -18,7 +18,7 @@ model Listing { wantId String @db.Uuid want Want @relation(fields: [wantId], references: [id], onDelete: Cascade, onUpdate: Cascade) - offers Offer[] + offers Offer[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@ -67,12 +67,13 @@ model Offer { status String item Decimal @db.Money + // markup Decimal @db.Money shipping Decimal @db.Money total Decimal @db.Money comparison Decimal @db.Money listingId Int - listing Listing @relation(fields: [listingId], references: [id], onDelete: Restrict) + listing Listing @relation(fields: [listingId], references: [id]) userId String @db.Uuid user User @relation(fields: [userId], references: [id], onDelete: Cascade) diff --git a/api/src/events.ts b/api/src/events.ts index 3dcfe89..b5e9444 100644 --- a/api/src/events.ts +++ b/api/src/events.ts @@ -27,6 +27,7 @@ export default function createEvents(log: Log, pg: Pg, discogs, offers) { await setTimeout(60 * 1000); return populateListings(want); } + throw e; } } diff --git a/api/src/offers.ts b/api/src/offers.ts index a27fcac..5892361 100644 --- a/api/src/offers.ts +++ b/api/src/offers.ts @@ -10,8 +10,9 @@ import { Pg } from './pg'; export enum Status { Pending = 'pending', Accepted = 'accepted', + Declined = 'declined', Ordered = 'ordered', - Delivered = 'delivered', + Complete = 'complete', } export default function createOffers(log: Log, pg: Pg) { diff --git a/api/src/pg.ts b/api/src/pg.ts index c1faa27..fac1935 100644 --- a/api/src/pg.ts +++ b/api/src/pg.ts @@ -2,7 +2,7 @@ import bcrypt from 'bcrypt'; import type Log from 'bunyan'; import type { PrismaClient, Want, User, Listing, Offer, Prisma } from '@prisma/client'; import * as Bluebird from 'bluebird'; -import omit from 'lodash/omit'; +import _ from 'lodash'; import { Status } from './offers'; @@ -123,17 +123,56 @@ export default function createPg(log: Log, prisma: PrismaClient): Pg { }); } - async function listingRmUnlisted(want: Want, ids: DiscogsListing[]) { - const { count } = await prisma.listing.deleteMany({ - where: { - wantId: want.id, - id: { - notIn: ids, - } - } - }); + async function listingRmUnlisted(want: Want, currentListingIds: DiscogsListing[]) { + return prisma.$transaction(async (prisma) => { + log.debug({ currentListingIds }); - return count; + const openOfferStatuses = [Status.Pending, Status.Accepted]; + + // can't delete a listing with an open offer + // so delete those offers first + const { count: offersRemoved } = await prisma.offer.deleteMany({ + where: { + wantId: want.id, + listingId: { + notIn: currentListingIds, + }, + status: { + in: openOfferStatuses, + }, + } + }); + + if (offersRemoved > 0) log.info({ offersRemoved }, 'open offers removed'); + + // now we have to filter listingIds with confirmed offers + // and get their listingIds to filter out + const confirmedListingIds = (await prisma.offer.findMany({ + where: { + wantId: want.id, + status: { + notIn: openOfferStatuses, + } + }, + select: { + listingId: true, + } + })).map(r => r.listingId); + const removalIds = _.without(currentListingIds, ...confirmedListingIds); + + // finally we delete listings that aren't related + // to a historical offer + const { count } = await prisma.listing.deleteMany({ + where: { + wantId: want.id, + id: { + notIn: currentListingIds, + } + } + }); + + return count; + }); } async function listingUpsert(listing, want) { @@ -214,7 +253,7 @@ export default function createPg(log: Log, prisma: PrismaClient): Pg { listingId: offer.listingId, }, create: offer, - update: omit(offer, ['status']), + update: _.omit(offer, ['status']), })) ); } diff --git a/client/src/actions.ts b/client/src/actions.ts index 01e154b..70326b5 100644 --- a/client/src/actions.ts +++ b/client/src/actions.ts @@ -2,6 +2,10 @@ import { route } from 'preact-router'; import http from './http'; const actions = store => ({ + setWs: function setWs(state, ws) { + return { ws }; + }, + setUser: function setUser(state, user) { return { user }; }, diff --git a/client/src/app.tsx b/client/src/app.tsx index ee59a6c..3a9a52d 100644 --- a/client/src/app.tsx +++ b/client/src/app.tsx @@ -26,11 +26,12 @@ async function init() { if (error) return route('/login'); route('/bundles'); store.setState({ user }); + store.setState({ ws }); } init(); -const App = () =>{ +const App = () => { return (
diff --git a/client/src/http.ts b/client/src/http.ts index 512071b..0ce4500 100644 --- a/client/src/http.ts +++ b/client/src/http.ts @@ -96,6 +96,13 @@ const actions = { id, }); }, + + postOfferStatus: async function postOfferStatus(id, status) { + return api.post('/acp/offer/status', { + id, + status, + }); + }, }; export default actions; diff --git a/client/src/routes/acp.tsx b/client/src/routes/acp.tsx index 320b661..79b8fe9 100644 --- a/client/src/routes/acp.tsx +++ b/client/src/routes/acp.tsx @@ -1,12 +1,22 @@ import { h } from 'preact'; import { useState, useEffect } from 'preact/hooks'; +import { connect } from 'unistore/preact' import http from './../http'; import AcpOffer from './../components/acp.offer'; -function Item(item) { +import { Status } from './../../../api/src/offers'; +function ItemEl({ item, ws }) { console.log(item); + console.log(ws); + const statuses = Object.entries(Status).map(([label, value]) => ( + + )); + + function onChange(e) { + console.log(item.id, e.target.value); + } return (
@@ -15,10 +25,15 @@ function Item(item) {
{item.total}
{item.status}
+
); } +const Item = connect(['ws'], {}, ItemEl); + function SellerGroup(group) { return (
@@ -29,7 +44,7 @@ function SellerGroup(group) {
- {group.offers.map(Item)} + {group.offers.map(i => )}
) diff --git a/client/src/store.tsx b/client/src/store.tsx index b6276cb..d9d2f44 100644 --- a/client/src/store.tsx +++ b/client/src/store.tsx @@ -5,5 +5,6 @@ export default function createStore() { bundles: [], offers: [], user: null, + ws: null, }); }; diff --git a/docker-compose.yaml b/docker-compose.yaml index b64b4f7..27f8e45 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -31,6 +31,7 @@ services: - '8080:8080' # fwd the hmr websocket volumes: - "./client:/opt/mcrates/client" + - "./api:/opt/mcrates/api" nginx: image: nginx:latest