409 lines
12 KiB
JavaScript
409 lines
12 KiB
JavaScript
import _ from "lodash";
|
|
import { outBid, pushPrice, updateBid } from "../../system/apis/bid.js";
|
|
import { sendMessage } from "../../system/apis/notification.js";
|
|
import { createOutBidLog } from "../../system/apis/out-bid-log.js";
|
|
import configs from "../../system/config.js";
|
|
import CONSTANTS from "../../system/constants.js";
|
|
import {
|
|
convertAETtoUTC,
|
|
isTimeReached,
|
|
removeFalsyValues,
|
|
takeSnapshot,
|
|
} from "../../system/utils.js";
|
|
import { ProductBid } from "../product-bid.js";
|
|
import axios from "../../system/axios.js";
|
|
|
|
export class AllbidsProductBid extends ProductBid {
|
|
constructor({ ...prev }) {
|
|
super(prev);
|
|
}
|
|
|
|
async waitForApiResponse() {
|
|
if (!this.page_context) return;
|
|
try {
|
|
// Chờ cho Angular load (có thể tùy chỉnh thời gian nếu cần)
|
|
await this.page_context.waitForFunction(
|
|
() => window.angular !== undefined
|
|
);
|
|
|
|
const auctionData = await this.page_context.evaluate(() => {
|
|
let data = null;
|
|
const elements = document.querySelectorAll(".ng-scope");
|
|
|
|
for (let i = 0; i < elements.length; i++) {
|
|
try {
|
|
const scope = angular.element(elements[i]).scope();
|
|
if (
|
|
scope?.auction &&
|
|
scope?.auction.aucID === this.model &&
|
|
scope?.auction?.aucBidIncrement
|
|
) {
|
|
data = scope.auction;
|
|
break;
|
|
}
|
|
|
|
// Thử lấy từ $parent nếu không thấy
|
|
if (scope?.$parent?.auction) {
|
|
data = scope.$parent.auction;
|
|
break;
|
|
}
|
|
} catch (e) {
|
|
// Angular element có thể lỗi nếu phần tử không hợp lệ
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return data;
|
|
});
|
|
|
|
return auctionData;
|
|
} catch (error) {
|
|
console.log(
|
|
`[${this.id}] Error in waitForApiResponse: ${error?.message}`
|
|
);
|
|
}
|
|
}
|
|
|
|
async getHistoriesData() {
|
|
if (!this.page_context) return;
|
|
try {
|
|
// Chờ cho Angular load (có thể tùy chỉnh thời gian nếu cần)
|
|
await this.page_context.waitForFunction(
|
|
() => window.angular !== undefined
|
|
);
|
|
|
|
const historiesData = await this.page_context.evaluate((model) => {
|
|
let data = null;
|
|
const elements = document.querySelectorAll(".ng-scope");
|
|
|
|
for (let i = 0; i < elements.length; i++) {
|
|
try {
|
|
const scope = angular.element(elements[i]).scope();
|
|
if (
|
|
scope &&
|
|
scope.auction &&
|
|
scope?.auction.aucID === model &&
|
|
scope?.bidHistory
|
|
) {
|
|
data = scope.bidHistory;
|
|
break;
|
|
}
|
|
|
|
// Thử lấy từ $parent nếu không thấy
|
|
if (scope?.$parent?.bidHistory) {
|
|
data = scope.$parent.bidHistory;
|
|
break;
|
|
}
|
|
} catch (e) {
|
|
// Angular element có thể lỗi nếu phần tử không hợp lệ
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}, this.model);
|
|
|
|
return historiesData;
|
|
} catch (error) {
|
|
console.log(
|
|
`[${this.id}] Error in waitForApiResponse: ${error?.message}`
|
|
);
|
|
}
|
|
}
|
|
|
|
async handleUpdateBid({
|
|
lot_id,
|
|
close_time,
|
|
name,
|
|
current_price,
|
|
reserve_price,
|
|
model,
|
|
metadata,
|
|
}) {
|
|
const response = await updateBid(this.id, {
|
|
lot_id,
|
|
close_time,
|
|
name,
|
|
current_price,
|
|
reserve_price: Number(reserve_price) || 0,
|
|
model,
|
|
metadata,
|
|
});
|
|
|
|
if (response) {
|
|
this.lot_id = response.lot_id;
|
|
this.close_time = response.close_time;
|
|
this.start_bid_time = response.start_bid_time;
|
|
}
|
|
}
|
|
|
|
async handlePlaceBidLive() {
|
|
if (!this.page_context) return;
|
|
|
|
const response = await this.page_context.evaluate(
|
|
async (aucID, bidAmount, submitUrl) => {
|
|
try {
|
|
const url = `${submitUrl}?aucID=${aucID}&bidAmount=${bidAmount}`;
|
|
|
|
const res = await fetch(url, {
|
|
method: "POST",
|
|
});
|
|
|
|
if (!res.ok) {
|
|
return { success: false, message: `HTTP error ${res.status}` };
|
|
}
|
|
|
|
const data = await res.json();
|
|
|
|
return data;
|
|
} catch (error) {
|
|
return { success: false, message: error.message || "Fetch failed" };
|
|
}
|
|
},
|
|
this.model,
|
|
this.max_price,
|
|
configs.WEB_CONFIGS.ALLBIDS.PLACE_BID
|
|
);
|
|
|
|
return response;
|
|
}
|
|
|
|
async handlePlaceBidSanbox() {
|
|
if (!this.page_context) return;
|
|
|
|
const response = await this.page_context.evaluate(
|
|
async (aucID, submitUrl) => {
|
|
try {
|
|
const url = `${submitUrl}?aucID=${aucID}&bidAmount=${0}&bidType=maximum`;
|
|
|
|
const res = await fetch(url, {
|
|
method: "POST",
|
|
});
|
|
|
|
if (!res.ok) {
|
|
return { success: false, message: `HTTP error ${res.status}` };
|
|
}
|
|
|
|
const data = await res.json();
|
|
|
|
return data;
|
|
} catch (error) {
|
|
return { success: false, message: error.message || "Fetch failed" };
|
|
}
|
|
},
|
|
this.model,
|
|
configs.WEB_CONFIGS.ALLBIDS.PLACE_BID
|
|
);
|
|
|
|
return response;
|
|
}
|
|
|
|
update = async () => {
|
|
if (!this.page_context) return;
|
|
|
|
console.log(`🔄 [${this.id}] Call update for ID: ${this.id}`);
|
|
|
|
// 📌 Chờ phản hồi API từ trang, tối đa 10 giây
|
|
const result = await this.waitForApiResponse();
|
|
|
|
const historiesData = await this.getHistoriesData();
|
|
|
|
// 📌 Nếu không có dữ liệu trả về thì dừng
|
|
if (!result) {
|
|
console.log(`⚠️ [${this.id}] No valid data received, skipping update.`);
|
|
return;
|
|
}
|
|
|
|
// 📌 Loại bỏ các giá trị không hợp lệ và bổ sung thông tin cần thiết
|
|
const data = removeFalsyValues(
|
|
{
|
|
// model: result?.pid || null,
|
|
lot_id: String(result?.aucCurrentBidID) || null,
|
|
reserve_price: result?.aucBidIncrement || null,
|
|
current_price: result.aucCurrentBid || null,
|
|
close_time: result?.aucCloseUtc
|
|
? new Date(result.aucCloseUtc).toUTCString()
|
|
: null,
|
|
// close_time: close_time && !this.close_time ? String(close_time) : null, // test
|
|
name: result?.aucTitle || null,
|
|
metadata: {
|
|
competor_histories: historiesData,
|
|
},
|
|
},
|
|
["close_time"]
|
|
);
|
|
|
|
console.log(`🚀 [${this.id}] Processed data ready for update`);
|
|
|
|
// 📌 Gửi dữ liệu cập nhật lên hệ thống
|
|
await this.handleUpdateBid(data);
|
|
|
|
console.log("✅ Update successful!");
|
|
|
|
return { ...response, name: data.name, close_time: data.close_time };
|
|
};
|
|
|
|
async handlePlaceBid() {
|
|
if (!this.page_context) {
|
|
console.log(
|
|
`⚠️ [${this.id}] No page context found, aborting bid process.`
|
|
);
|
|
return;
|
|
}
|
|
const page = this.page_context;
|
|
|
|
if (global[`IS_PLACE_BID-${this.id}`]) {
|
|
console.log(`⚠️ [${this.id}] Bid is already in progress, skipping.`);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
console.log(`🔄 [${this.id}] Starting bid process...`);
|
|
global[`IS_PLACE_BID-${this.id}`] = true;
|
|
|
|
// Đợi phản hồi từ API
|
|
const response = await this.waitForApiResponse();
|
|
|
|
if (
|
|
!response ||
|
|
isTimeReached(new Date(response.aucCloseUtc).toUTCString())
|
|
) {
|
|
console.log(
|
|
`⚠️ [${this.id}] Outbid detected, calling outBid function.`
|
|
);
|
|
await outBid(this.id);
|
|
return;
|
|
}
|
|
|
|
// Kiểm tra nếu giá hiện tại lớn hơn giá tối đa cộng thêm giá cộng thêm
|
|
if (this.current_price > this.max_price + this.plus_price) {
|
|
console.log(`⚠️ [${this.id}] Outbid bid`); // Ghi log cảnh báo nếu giá hiện tại vượt quá mức tối đa cho phép
|
|
return; // Dừng hàm nếu giá đã vượt qua giới hạn
|
|
}
|
|
|
|
// Kiểm tra thời gian bid
|
|
if (!this.start_bid_time || !isTimeReached(this.start_bid_time)) {
|
|
console.log(
|
|
`⏳ [${this.id}] Not yet time to bid. Skipping Product: ${
|
|
this.name || "None"
|
|
}`
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Kiểm tra nếu phản hồi không tồn tại hoặc nếu giá đấu của người dùng bằng với giá tối đa hiện tại
|
|
if (
|
|
!response ||
|
|
(response?.aucUserMaxBid && response.aucUserMaxBid == this.max_price) ||
|
|
response?.aucBidIncrement > this.max_price
|
|
) {
|
|
console.log(
|
|
`⚠️ [${this.id}] No response or myBid equals max_price:`,
|
|
response
|
|
); // Ghi log nếu không có phản hồi hoặc giá đấu của người dùng bằng giá tối đa
|
|
return; // Nếu không có phản hồi hoặc giá đấu bằng giá tối đa thì dừng hàm
|
|
}
|
|
|
|
const bidHistoriesItem = _.maxBy(this.histories, "price");
|
|
console.log(`📜 [${this.id}] Current bid history:`, this.histories);
|
|
|
|
if (
|
|
bidHistoriesItem &&
|
|
bidHistoriesItem?.price === this.current_price &&
|
|
this.max_price == response?.aucUserMaxBid
|
|
) {
|
|
console.log(
|
|
`🔄 [${this.id}] You have already bid on this item! (Bid Price: ${bidHistoriesItem.price})`
|
|
);
|
|
return;
|
|
}
|
|
|
|
console.log("---------------------BIDDING--------------------");
|
|
|
|
if (this.isSandbox()) {
|
|
await this.handleCallActionSanbox();
|
|
} else {
|
|
await this.handleCallActionLive();
|
|
}
|
|
} catch (error) {
|
|
console.log(`🚨 [${this.id}] Error placing bid: ${error.message}`);
|
|
} finally {
|
|
console.log(`🔚 [${this.id}] Resetting bid flag.`);
|
|
global[`IS_PLACE_BID-${this.id}`] = false;
|
|
}
|
|
}
|
|
|
|
async handleCallActionLive() {
|
|
const data = await this.handlePlaceBidLive();
|
|
|
|
await this.page_context.reload({ waitUntil: "networkidle0" });
|
|
|
|
// const { aucUserMaxBid } = await this.waitForApiResponse();
|
|
console.log(`📡 [${this.id}] API Response received:`, {
|
|
aucUserMaxBid: this.max_price,
|
|
});
|
|
|
|
// 📌 Kiểm tra trạng thái đấu giá từ API
|
|
if (
|
|
data?.bidResult?.result ||
|
|
data?.bidResult?.bidAmount == this.max_price
|
|
) {
|
|
console.log(`📸 [${this.id}] Taking bid success snapshot...`);
|
|
|
|
// sendMessage(this);
|
|
|
|
pushPrice({
|
|
bid_id: this.id,
|
|
price: this.max_price,
|
|
});
|
|
|
|
await takeSnapshot(
|
|
this.page_context,
|
|
this,
|
|
"bid-success",
|
|
CONSTANTS.TYPE_IMAGE.SUCCESS
|
|
);
|
|
|
|
console.log(`✅ [${this.id}] Bid placed successfully!`);
|
|
return;
|
|
}
|
|
|
|
console.log(
|
|
`⚠️ [${this.id}] Bid action completed, but status is still "None".`
|
|
);
|
|
}
|
|
|
|
async handleCallActionSanbox() {
|
|
const result = await this.handlePlaceBidSanbox();
|
|
|
|
await axios({
|
|
url: this.ACTION_URL({ type: "api" }),
|
|
data: {
|
|
id: this.id,
|
|
data: JSON.stringify(result),
|
|
},
|
|
method: "POST",
|
|
});
|
|
|
|
await this.close();
|
|
|
|
return result;
|
|
}
|
|
|
|
action = async () => {
|
|
try {
|
|
const page = this.page_context;
|
|
|
|
// 📌 Kiểm tra nếu trang chưa tải đúng URL thì điều hướng đến URL mục tiêu
|
|
if (!page.url() || !page.url().includes(this.url)) {
|
|
console.log(`🔄 [${this.id}] Navigating to target URL: ${this.url}`);
|
|
await this.gotoLink();
|
|
}
|
|
|
|
await this.handlePlaceBid();
|
|
} catch (error) {
|
|
console.error(`🚨 [${this.id}] Error navigating the page: ${error}`);
|
|
}
|
|
};
|
|
}
|