bid-tool/auto-bid-tool/models/grays.com/grays-product-bid copy.js

323 lines
8.5 KiB
JavaScript

import {
outBid,
pushPrice,
updateBid,
updateStatusByPrice,
} from "../../system/apis/bid.js";
import CONSTANTS from "../../system/constants.js";
import {
delay,
extractNumber,
isNumber,
isTimeReached,
removeFalsyValues,
safeClosePage,
takeSnapshot,
} from "../../system/utils.js";
import { ProductBid } from "../product-bid.js";
export class GraysProductBidBackup extends ProductBid {
constructor({ ...prev }) {
super(prev);
}
async validate({ page, price_value }) {
if (!this.start_bid_time || !isTimeReached(this.start_bid_time)) {
console.log(`❌ [${this.id}] It's not time yet`);
return { result: false, bid_price: 0 };
}
if (!isNumber(price_value)) {
console.log(`❌ [${this.id}] Can't get PRICE_VALUE`);
await takeSnapshot(page, this, "price-value-null");
return { result: false, bid_price: 0 };
}
const bid_price = this.plus_price + Number(price_value);
if (bid_price > this.max_price) {
console.log(
`${this.id} PRICE BID is more than MAX_VALUE => STOP BID THIS PRODUCT`
);
await takeSnapshot(page, this, "price-bid-more-than");
await outBid(this.id);
return { result: false, bid_price: 0 };
}
const response = await pushPrice({
bid_id: this.id,
price: bid_price,
});
if (!response.status) {
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() {
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(`❌ [${this.id}] Product is close ${close_time}`);
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(`❌ [${this.id}] Timeout to loading`);
await takeSnapshot(page, this, "timeout to loading");
return false;
}
}
async handleReturnProductPage(page) {
await page.goto(this.url);
await delay(1000);
}
async handleUpdateBid({
lot_id,
close_time,
name,
current_price,
reserve_price,
}) {
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;
}
}
update = async () => {
if (!this.page_context) return;
const page = this.page_context;
try {
const close_time = await this.getCloseTime();
// Chờ phần tử xuất hiện trước khi lấy giá trị
await page
.waitForSelector("#priceValue", { timeout: 5000 })
.catch(() => null);
const price_value = await page
.$eval("#priceValue", (el) => el.value)
.catch(() => null);
await page.waitForSelector("#lotId", { timeout: 5000 }).catch(() => null);
const lot_id = await page
.$eval("#lotId", (el) => el.value)
.catch(() => null);
await page
.waitForSelector("#placebid-sticky > div:nth-child(2) > div > h3", {
timeout: 5000,
})
.catch(() => null);
const name = await page
.$eval(".dls-heading-3.lotPageTitle", (el) => el.innerText)
.catch(() => null);
await page
.waitForSelector(
"#biddableLot > form > div > div:nth-child(1) > div:nth-child(1) > div:nth-child(2) > div > span > span",
{ timeout: 5000 }
)
.catch(() => 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
)
.catch(() => null);
console.log(
`📌 [${this.id}] Product Info: Lot ID: ${lot_id}, Name: ${name}, Current Price: ${current_price}, Reserve price: ${price_value}`
);
const data = removeFalsyValues(
{
lot_id,
reserve_price: price_value,
close_time: close_time ? String(close_time) : null,
name,
current_price: current_price ? extractNumber(current_price) : null,
},
["close_time"]
);
this.handleUpdateBid(data);
return { price_value, lot_id, name, current_price };
} catch (error) {
console.error(`🚨 Error updating product info: ${error.message}`);
return null;
}
};
action = async () => {
try {
const page = this.page_context;
await this.gotoLink();
console.log(`🌍 [${this.id}] Navigated to link.`);
await delay(1000);
const { close_time, ...isCloseProduct } = await this.isCloseProduct();
if (isCloseProduct.result) {
console.log(
`❌ [${this.id}] The product is closed, cannot place a bid.`
);
return;
}
await delay(500);
const { price_value } = await this.update();
if (!price_value) return;
const { result, bid_price } = await this.validate({ page, price_value });
if (!result) {
console.log(
`❌ [${this.id}] Validation failed. Unable to proceed with bidding.`
);
return;
}
const bidHistoriesItem = _.maxBy(this.histories, "price");
if (bidHistoriesItem && bidHistoriesItem.price === this.current_price) {
console.log(
`🔄 [${this.id}] You have already bid on this item! (Bid Price: ${bidHistoriesItem.price})`
);
return;
}
if (price_value != bid_price) {
console.log(
`✍️ [${this.id}] Updating bid price from ${price_value}${bid_price}`
);
await this.handleWritePrice(page, bid_price);
}
console.log(`🚀 [${this.id}] Placing the bid...`);
const resultPlaceBid = await this.placeBid(page);
if (!resultPlaceBid) {
console.log(`❌ [${this.id}] Error occurred while placing the bid.`);
await takeSnapshot(page, this, "place-bid-action");
return;
}
console.log(
`✅ [${this.id}] Bid placed successfully! 🏆 Bid Price: ${bid_price}, Closing Time: ${close_time}`
);
await this.handleReturnProductPage(page);
} catch (error) {
console.error(
`🚨 [${this.id}] Error navigating the page: ${error.message}`
);
}
};
}