219 lines
7.6 KiB
JavaScript
219 lines
7.6 KiB
JavaScript
import { outBid, pushPrice, updateBid, updateStatusByPrice } from '../../system/apis/bid.js';
|
|
import CONSTANTS from '../../system/constants.js';
|
|
import { delay, extractNumber, isNumber, isTimeReached, safeClosePage, takeSnapshot } from '../../system/utils.js';
|
|
import { ProductBid } from '../product-bid.js';
|
|
|
|
export class GraysProductBid extends ProductBid {
|
|
constructor({ ...prev }) {
|
|
super(prev);
|
|
}
|
|
|
|
async validate({ page, price_value }) {
|
|
if (!this.start_bid_time || !isTimeReached(this.start_bid_time)) {
|
|
console.log("It's not time yet ❌");
|
|
return { result: false, bid_price: 0 };
|
|
}
|
|
|
|
if (!isNumber(price_value)) {
|
|
console.log("Can't get PRICE_VALUE ❌");
|
|
await takeSnapshot(page, this, 'price-value-null');
|
|
await safeClosePage(this);
|
|
|
|
return { result: false, bid_price: 0 };
|
|
}
|
|
|
|
const bid_price = this.plus_price + Number(price_value);
|
|
|
|
if (bid_price > this.max_price) {
|
|
console.log('PRICE BID is more than MAX_VALUE => STOP BID THIS PRODUCT ❌');
|
|
await takeSnapshot(page, this, 'price-bid-more-than');
|
|
await safeClosePage(this);
|
|
|
|
await outBid(this.id);
|
|
|
|
return { result: false, bid_price: 0 };
|
|
}
|
|
|
|
const response = await pushPrice({
|
|
bid_id: this.id,
|
|
price: bid_price,
|
|
});
|
|
|
|
if (!response.status) {
|
|
// await this.handleReturnProductPage(page);
|
|
await safeClosePage(this);
|
|
return { result: false, bid_price: 0 };
|
|
}
|
|
|
|
this.histories = response.data;
|
|
|
|
// RESET first bid
|
|
if (this.histories.length > 0 && this.first_bid) {
|
|
this.first_bid = false;
|
|
}
|
|
|
|
return { result: true, bid_price };
|
|
}
|
|
|
|
getCloseTime = async () => {
|
|
try {
|
|
if (!this.page_context) return null;
|
|
|
|
await this.page_context.waitForSelector('#lot-closing-datetime', { timeout: 3000 });
|
|
|
|
return await this.page_context.$eval('#lot-closing-datetime', (el) => el.value);
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
getPriceWasBid = async () => {
|
|
try {
|
|
if (!this.page_context) return null;
|
|
|
|
await this.page_context.waitForSelector('#biddableLot form div div:nth-child(1) span span', { timeout: 3000 });
|
|
|
|
const element = await this.page_context.$('#biddableLot form div div:nth-child(1) span span');
|
|
|
|
const textPrice = await this.page_context.evaluate((el) => el.textContent, element);
|
|
|
|
return extractNumber(textPrice) || null;
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
async isCloseProduct(page) {
|
|
const close_time = await this.getCloseTime();
|
|
|
|
if (!close_time) {
|
|
const priceWasBid = await this.getPriceWasBid();
|
|
|
|
await updateStatusByPrice(this.id, priceWasBid);
|
|
return { result: true, close_time: null };
|
|
}
|
|
|
|
await delay(500);
|
|
|
|
if (!close_time || new Date(close_time).getTime() <= new Date().getTime()) {
|
|
console.log(`Product is close ${close_time} ❌`);
|
|
await safeClosePage(this);
|
|
return { result: true, close_time };
|
|
}
|
|
|
|
return { result: false, close_time };
|
|
}
|
|
|
|
async handleWritePrice(page, bid_price) {
|
|
await page.type('#price', String(bid_price));
|
|
await delay(500);
|
|
}
|
|
|
|
async placeBid(page) {
|
|
try {
|
|
await page.click('#bid-type-standard');
|
|
await delay(500);
|
|
|
|
await page.click('#btnSubmit');
|
|
await delay(1000);
|
|
|
|
await page.waitForSelector('button', { timeout: 5000 });
|
|
|
|
await delay(500);
|
|
|
|
await page.click('button');
|
|
|
|
await page.waitForNavigation({ timeout: 5000 });
|
|
|
|
await takeSnapshot(page, this, 'bid-success', CONSTANTS.TYPE_IMAGE.SUCCESS);
|
|
return true;
|
|
} catch (error) {
|
|
console.log({ error: error.message });
|
|
console.log('❌ Timeout to loading');
|
|
await takeSnapshot(page, this, 'timeout to loading');
|
|
await safeClosePage(this);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async handleReturnProductPage(page) {
|
|
await page.goto(this.url);
|
|
await delay(1000);
|
|
}
|
|
|
|
async handleUpdateBid({ lot_id, close_time, name, current_price, reserve_price }) {
|
|
if (close_time && this.close_time == close_time) return;
|
|
|
|
const response = await updateBid(this.id, { lot_id, close_time, name, current_price, reserve_price: Number(reserve_price) || 0 });
|
|
|
|
if (response) {
|
|
this.lot_id = response.lot_id;
|
|
this.close_time = response.close_time;
|
|
this.start_bid_time = response.start_bid_time;
|
|
}
|
|
}
|
|
|
|
action = async () => {
|
|
try {
|
|
const page = this.page_context;
|
|
console.log('🔄 Starting the bidding process...');
|
|
|
|
await page.goto(this.url, { waitUntil: 'networkidle2' });
|
|
console.log(`✅ Navigated to: ${this.url}`);
|
|
|
|
await page.bringToFront();
|
|
console.log('👀 Brought the tab to the foreground.');
|
|
|
|
await delay(1000);
|
|
// this.handleTakeWorkSnapshot();
|
|
|
|
const { close_time, ...isCloseProduct } = await this.isCloseProduct(page);
|
|
if (isCloseProduct.result) {
|
|
console.log('❌ The product is closed, cannot place a bid.');
|
|
return;
|
|
}
|
|
|
|
await delay(500);
|
|
|
|
const price_value = (await page.$eval('#priceValue', (el) => el.value)) || null;
|
|
const lot_id = await page.$eval('#lotId', (el) => el.value);
|
|
const name = (await page.$eval('#placebid-sticky > div:nth-child(2) > div > h3', (el) => el.innerText)) || null;
|
|
const current_price =
|
|
(await page.$eval('#biddableLot > form > div > div:nth-child(1) > div:nth-child(1) > div:nth-child(2) > div > span > span', (el) => el.innerText)) || null;
|
|
|
|
console.log(`📌 Product Info: Lot ID: ${lot_id}, Name: ${name}, Current Price: ${current_price}, Reserve price ${price_value}`);
|
|
|
|
this.handleUpdateBid({ lot_id, reserve_price: price_value, close_time, name, current_price: current_price ? extractNumber(current_price) : null });
|
|
|
|
const { result, bid_price } = await this.validate({ page, price_value });
|
|
|
|
if (!result) {
|
|
console.log('❌ Validation failed. Unable to proceed with bidding.');
|
|
return;
|
|
}
|
|
|
|
if (price_value != bid_price) {
|
|
console.log(`✍️ Updating bid price from ${price_value} → ${bid_price}`);
|
|
await this.handleWritePrice(page, bid_price);
|
|
}
|
|
|
|
console.log('🚀 Placing the bid...');
|
|
const resultPlaceBid = await this.placeBid(page);
|
|
|
|
if (!resultPlaceBid) {
|
|
console.log('❌ Error occurred while placing the bid.');
|
|
await takeSnapshot(page, this, 'place-bid-action');
|
|
await safeClosePage(this);
|
|
return;
|
|
}
|
|
|
|
console.log(`✅ Bid placed successfully! 🏆 Bid Price: ${bid_price}, Closing Time: ${close_time}`);
|
|
|
|
await this.handleReturnProductPage(page);
|
|
} catch (error) {
|
|
console.error(`🚨 Error navigating the page: ${error.message}`);
|
|
safeClosePage(this);
|
|
}
|
|
};
|
|
}
|