simplify and automate offer creation

This commit is contained in:
ntr committed 2022-09-02 00:06:51 +10:00
1 parent 7ea2c37116
commit a43d4f32e4
10 files changed
+97 -67

No files matched your search

+2 -1
View File
@@ -28,7 +28,8 @@ async function start() {
events,
} = createServices(log);
events.emit(Events.StartupSync);
// events.emit(Events.StartupSync);
events.emit(Events.ListingsUpdated);
await api.listen();
}
+2 -1
View File
@@ -81,6 +81,7 @@ model Offer {
want Want @relation(fields: [wantId], references: [id], onDelete: Cascade, onUpdate: Cascade)
// only one offer per want for a user
@@unique([userId, wantId])
// @@unique([userId, wantId])
@@unique([listingId])
@@map("offers")
}
+1 -41
View File
@@ -37,46 +37,6 @@ export default function createApi(log: Log, pg: Pg, discogs, offers, events) {
const router = koaRouter();
interface ListingData extends Listing {
data: any,
want: { user: User },
};
async function getBundles() {
const bundles = await pg.bundleCandidates();
return bundles.map((b: ListingData[]) => {
const total = b.reduce((acc, l) => acc + l.data.price.value, 0);
const items = b.map(l => ({
id: l.data.id,
description: l.data.release.description,
originalPrice: l.data.original_price.value,
originalCurrency: l.data.original_price.curr_abbr,
price: l.data.price.value,
currency: l.data.price.currency,
condition: l.data.condition,
uri: l.data.uri,
user: l.want.user,
}));
const shipping = b[0]?.data.seller.shipping;
const bundle = {
username: b[0]?.data.seller.username,
seller: b[0]?.data.seller.id,
shipsFrom: b[0]?.data.ships_from,
total,
currency: b[0]?.data.price.currency,
shipping: '...',
items,
mentionsAustralia: shipping.toLowerCase().includes('australia'),
mentionsWorldwide: shipping.toLowerCase().includes('world'),
}
return bundle;
});
}
function listen() {
return new Promise((resolve, reject) => {
app.on('error', err => {
@@ -105,7 +65,7 @@ export default function createApi(log: Log, pg: Pg, discogs, offers, events) {
});
router.get('/acp/bundles', async function bundlesGet(ctx, next) {
const bundles = await getBundles();
const bundles = await offers.bundles();
ctx.response.body = bundles;
})
+28 -1
View File
@@ -11,9 +11,10 @@ import routerAuth from './routers/router.auth';
export enum Events {
WantsAdded = 'WantsAdded',
StartupSync = 'StartupSync',
ListingsUpdated = 'ListingsUpdated',
}
export default function createEvents(log: Log, pg: Pg, discogs) {
export default function createEvents(log: Log, pg: Pg, discogs, offers) {
const events = new EventEmitter({ captureRejections: true });
events.on('error', function eventError(e) {
@@ -50,5 +51,31 @@ export default function createEvents(log: Log, pg: Pg, discogs) {
});
events.on(Events.ListingsUpdated, async function listingsUpdated() {
const bundles = await offers.bundles();
log.info({ event: Events.ListingsUpdated, bundles: bundles.length });
// const bundle = {
// username: b[0]?.data.seller.username,
// seller: b[0]?.data.seller.id,
// shipsFrom: b[0]?.data.ships_from,
// total,
// currency: b[0]?.data.price.currency,
// shipping: '...',
// items,
// mentionsAustralia: shipping.toLowerCase().includes('australia'),
// mentionsWorldwide: shipping.toLowerCase().includes('world'),
// }
for (const bundle of bundles) {
log.info({ seller: bundle.seller, items: bundle.items.length }, 'generating offers...');
const listingIds = bundle.items.map(i => i.id);
const updatedOffers = await offers.generate(listingIds, 100, 30)
log.info({ offers: updatedOffers.length }, 'offers set');
}
log.info('offers up to date');
});
return events;
}
+46 -2
View File
@@ -19,9 +19,11 @@ export default function createOffers(log: Log, pg: Pg) {
log.info('generateOffers', { listingIds, bulkShipping, baseShipping });
const listings = await pg.listingByIds(listingIds);
log.info({ listings }, 'creating offers for listings')
// log.info({ listings }, 'creating offers for listings')
const shipping = bulkShipping / listings.length;
const shipping = 10 + Math.random(); // yolt
// const shipping = bulkShipping / listings.length;
// how to deal with users who don't want all items in a bundle...
const offers = listings.map(l => ({
@@ -60,8 +62,50 @@ export default function createOffers(log: Log, pg: Pg) {
return pg.offerSetStatus(offer.id, Status.Accepted);
}
async function bundles() {
const bundles = await pg.bundleCandidates();
interface ListingData extends Listing {
data: any,
want: { user: User },
};
return bundles.map((b: ListingData[]) => {
const total = b.reduce((acc, l) => acc + l.data.price.value, 0);
const items = b.map(l => ({
id: l.data.id,
description: l.data.release.description,
originalPrice: l.data.original_price.value,
originalCurrency: l.data.original_price.curr_abbr,
price: l.data.price.value,
currency: l.data.price.currency,
condition: l.data.condition,
uri: l.data.uri,
user: l.want.user,
}));
const shipping = b[0]?.data.seller.shipping;
const bundle = {
username: b[0]?.data.seller.username,
seller: b[0]?.data.seller.id,
shipsFrom: b[0]?.data.ships_from,
total,
currency: b[0]?.data.price.currency,
shipping: '...',
items,
mentionsAustralia: shipping.toLowerCase().includes('australia'),
mentionsWorldwide: shipping.toLowerCase().includes('world'),
}
return bundle;
});
}
return {
generate,
accept,
bundles,
};
}
+6 -6
View File
@@ -2,6 +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 { Status } from './offers';
@@ -54,7 +55,7 @@ export default function createPg(log: Log, prisma: PrismaClient): Pg {
want: true,
},
orderBy: {
status: 'desc',
total: 'asc',
},
});
}
@@ -184,6 +185,8 @@ export default function createPg(log: Log, prisma: PrismaClient): Pg {
seller, count(distinct("wantId")), array_agg(id) as listings
from
listings
where
seller not in (3709203)
group by
seller
order by
@@ -208,13 +211,10 @@ export default function createPg(log: Log, prisma: PrismaClient): Pg {
return await prisma.$transaction(
offers.map(offer => prisma.offer.upsert({
where: {
userId_wantId: {
userId: offer.userId,
wantId: offer.wantId,
},
listingId: offer.listingId,
},
create: offer,
update: offer
update: omit(offer, ['status']),
}))
);
}
+1 -1
View File
@@ -11,8 +11,8 @@ export default function creates(log) {
const prisma = new PrismaClient();
const pg = createPg(log, prisma);
const discogs = createDiscogs(log, pg);
const events = createEvents(log, pg, discogs);
const offers = createOffers(log, pg);
const events = createEvents(log, pg, discogs, offers);
const api = createApi(log, pg, discogs, offers, events);
return {