diff --git a/package-lock.json b/package-lock.json index ae4317a5..95bfdf39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "copyfiles": "^2.4.1", "express": "^5", "mongoose": "^8.9.2", - "warframe-public-export-plus": "^0.5.18", + "warframe-public-export-plus": "^0.5.19", "warframe-riven-info": "^0.1.2", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" @@ -3778,9 +3778,9 @@ } }, "node_modules/warframe-public-export-plus": { - "version": "0.5.18", - "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.18.tgz", - "integrity": "sha512-wUaW5Ua5tXHOYkKJxbealdCcTnRLUN7UCkvYOJEwlB/H14EBzDaqxg4engGqzbq4H8fmttyp3EUo4vazSaxZWg==" + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.19.tgz", + "integrity": "sha512-ERCPAe4ojJXts6tyNPBvNsFcgAwJuV3M04iDfXhudJfpJrg0qseDO4AExjSyFo+WUvKoWROMCy9dCRzxIbNATw==" }, "node_modules/warframe-riven-info": { "version": "0.1.2", diff --git a/package.json b/package.json index ed389137..4f789119 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "copyfiles": "^2.4.1", "express": "^5", "mongoose": "^8.9.2", - "warframe-public-export-plus": "^0.5.18", + "warframe-public-export-plus": "^0.5.19", "warframe-riven-info": "^0.1.2", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" diff --git a/src/app.ts b/src/app.ts index 4d02f79e..e167b0d2 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,16 +1,15 @@ import express from "express"; +import bodyParser from "body-parser"; import { unknownEndpointHandler } from "@/src/middleware/middleware"; import { requestLogger } from "@/src/middleware/morgenMiddleware"; +import { errorHandler } from "@/src/middleware/errorHandler"; import { apiRouter } from "@/src/routes/api"; -//import { testRouter } from "@/src/routes/test"; import { cacheRouter } from "@/src/routes/cache"; -import bodyParser from "body-parser"; - -import { steamPacksController } from "@/src/controllers/misc/steamPacksController"; import { customRouter } from "@/src/routes/custom"; import { dynamicController } from "@/src/routes/dynamic"; +import { payRouter } from "@/src/routes/pay"; import { statsRouter } from "@/src/routes/stats"; import { webuiRouter } from "@/src/routes/webui"; @@ -20,21 +19,16 @@ app.use(bodyParser.raw()); app.use(express.json()); app.use(bodyParser.text()); app.use(requestLogger); -//app.use(requestLogger); app.use("/api", apiRouter); -//app.use("/test", testRouter); app.use("/", cacheRouter); app.use("/custom", customRouter); app.use("/:id/dynamic", dynamicController); - -app.post("/pay/steamPacks.php", steamPacksController); +app.use("/pay", payRouter); app.use("/stats", statsRouter); - app.use("/", webuiRouter); app.use(unknownEndpointHandler); - -//app.use(errorHandler) +app.use(errorHandler); export { app }; diff --git a/src/controllers/api/claimCompletedRecipeController.ts b/src/controllers/api/claimCompletedRecipeController.ts index 237a5b87..5b8e048e 100644 --- a/src/controllers/api/claimCompletedRecipeController.ts +++ b/src/controllers/api/claimCompletedRecipeController.ts @@ -30,13 +30,11 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) = recipe => recipe._id?.toString() === claimCompletedRecipeRequest.RecipeIds[0].$oid ); if (!pendingRecipe) { - logger.error(`no pending recipe found with id ${claimCompletedRecipeRequest.RecipeIds[0].$oid}`); throw new Error(`no pending recipe found with id ${claimCompletedRecipeRequest.RecipeIds[0].$oid}`); } //check recipe is indeed ready to be completed // if (pendingRecipe.CompletionDate > new Date()) { - // logger.error(`recipe ${pendingRecipe._id} is not ready to be completed`); // throw new Error(`recipe ${pendingRecipe._id} is not ready to be completed`); // } @@ -45,7 +43,6 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) = const recipe = getRecipe(pendingRecipe.ItemType); if (!recipe) { - logger.error(`no completed item found for recipe ${pendingRecipe._id.toString()}`); throw new Error(`no completed item found for recipe ${pendingRecipe._id.toString()}`); } @@ -83,11 +80,12 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) = ...(await updateCurrencyByAccountId(recipe.skipBuildTimePrice, true, accountId)) }; } - res.json({ - InventoryChanges: { - ...InventoryChanges, - ...(await addItem(accountId, recipe.resultType, recipe.num)).InventoryChanges - } - }); + const inventory = await getInventory(accountId); + InventoryChanges = { + ...InventoryChanges, + ...(await addItem(inventory, recipe.resultType, recipe.num)).InventoryChanges + }; + await inventory.save(); + res.json({ InventoryChanges }); } }; diff --git a/src/controllers/api/getCreditsController.ts b/src/controllers/api/creditsController.ts similarity index 75% rename from src/controllers/api/getCreditsController.ts rename to src/controllers/api/creditsController.ts index fdce3899..10ac10b3 100644 --- a/src/controllers/api/getCreditsController.ts +++ b/src/controllers/api/creditsController.ts @@ -3,14 +3,8 @@ import { config } from "@/src/services/configService"; import { getAccountIdForRequest } from "@/src/services/loginService"; import { getInventory } from "@/src/services/inventoryService"; -export const getCreditsController: RequestHandler = async (req, res) => { - let accountId; - try { - accountId = await getAccountIdForRequest(req); - } catch (e) { - res.status(400).send("Log-in expired"); - return; - } +export const creditsController: RequestHandler = async (req, res) => { + const accountId = await getAccountIdForRequest(req); const inventory = await getInventory(accountId); diff --git a/src/controllers/api/focusController.ts b/src/controllers/api/focusController.ts index 268b53ba..5468d8dd 100644 --- a/src/controllers/api/focusController.ts +++ b/src/controllers/api/focusController.ts @@ -4,6 +4,7 @@ import { getInventory, addMiscItems, addEquipment } from "@/src/services/invento import { IMiscItem, TFocusPolarity, TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes"; import { logger } from "@/src/utils/logger"; import { ExportFocusUpgrades } from "warframe-public-export-plus"; +import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes"; export const focusController: RequestHandler = async (req, res) => { const accountId = await getAccountIdForRequest(req); @@ -102,8 +103,10 @@ export const focusController: RequestHandler = async (req, res) => { "/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingChassis", "/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingBarrel" ]; - const result = await addEquipment("OperatorAmps", request.StartingWeaponType, accountId, parts); - res.json(result); + const inventory = await getInventory(accountId); + const inventoryChanges = addEquipment(inventory, "OperatorAmps", request.StartingWeaponType, parts); + await inventory.save(); + res.json((inventoryChanges.OperatorAmps as IEquipmentClient[])[0]); break; } case FocusOperation.UnbindUpgrade: { diff --git a/src/controllers/api/getShipController.ts b/src/controllers/api/getShipController.ts index 4dad54a8..3ce7a6c3 100644 --- a/src/controllers/api/getShipController.ts +++ b/src/controllers/api/getShipController.ts @@ -5,7 +5,6 @@ import { getAccountIdForRequest } from "@/src/services/loginService"; import { getPersonalRooms } from "@/src/services/personalRoomsService"; import { getShip } from "@/src/services/shipService"; import { Loadout } from "@/src/models/inventoryModels/loadoutModel"; -import { logger } from "@/src/utils/logger"; import { toOid } from "@/src/helpers/inventoryHelpers"; import { IGetShipResponse } from "@/src/types/shipTypes"; import { IPersonalRooms } from "@/src/types/personalRoomsTypes"; @@ -44,8 +43,7 @@ export const getLoadout = async (accountId: string) => { const loadout = await Loadout.findOne({ loadoutOwnerId: accountId }); if (!loadout) { - logger.error(`loadout not found for account ${accountId}`); - throw new Error("loadout not found"); + throw new Error(`loadout not found for account ${accountId}`); } return loadout; diff --git a/src/controllers/api/guildTechController.ts b/src/controllers/api/guildTechController.ts index 7d27267b..34022699 100644 --- a/src/controllers/api/guildTechController.ts +++ b/src/controllers/api/guildTechController.ts @@ -2,7 +2,7 @@ import { RequestHandler } from "express"; import { getGuildForRequestEx } from "@/src/services/guildService"; import { ExportDojoRecipes } from "warframe-public-export-plus"; import { getAccountIdForRequest } from "@/src/services/loginService"; -import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService"; +import { addMiscItems, addRecipes, getInventory, updateCurrency } from "@/src/services/inventoryService"; import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes"; import { IInventoryChanges } from "@/src/types/purchaseTypes"; @@ -11,11 +11,12 @@ export const guildTechController: RequestHandler = async (req, res) => { const inventory = await getInventory(accountId); const guild = await getGuildForRequestEx(req, inventory); const data = JSON.parse(String(req.body)) as TGuildTechRequest; - if (data.Action == "Sync") { + const action = data.Action.split(",")[0]; + if (action == "Sync") { res.json({ TechProjects: guild.toJSON().TechProjects }); - } else if (data.Action == "Start") { + } else if (action == "Start") { const recipe = ExportDojoRecipes.research[data.RecipeType!]; guild.TechProjects ??= []; if (!guild.TechProjects.find(x => x.ItemType == data.RecipeType)) { @@ -31,7 +32,7 @@ export const guildTechController: RequestHandler = async (req, res) => { } await guild.save(); res.end(); - } else if (data.Action == "Contribute") { + } else if (action == "Contribute") { const contributions = data as IGuildTechContributeFields; const techProject = guild.TechProjects!.find(x => x.ItemType == contributions.RecipeType)!; if (contributions.RegularCredits > techProject.ReqCredits) { @@ -70,6 +71,30 @@ export const guildTechController: RequestHandler = async (req, res) => { res.json({ InventoryChanges: inventoryChanges }); + } else if (action == "Buy") { + const purchase = data as IGuildTechBuyFields; + const quantity = parseInt(data.Action.split(",")[1]); + const inventory = await getInventory(accountId); + const recipeChanges = [ + { + ItemType: purchase.RecipeType, + ItemCount: quantity + } + ]; + addRecipes(inventory, recipeChanges); + const currencyChanges = updateCurrency( + inventory, + ExportDojoRecipes.research[purchase.RecipeType].replicatePrice, + false + ); + await inventory.save(); + // Not a mistake: This response uses `inventoryChanges` instead of `InventoryChanges`. + res.json({ + inventoryChanges: { + ...currencyChanges, + Recipes: recipeChanges + } + }); } else { throw new Error(`unknown guildTech action: ${data.Action}`); } @@ -85,6 +110,8 @@ interface IGuildTechStartFields { RecipeType: string; } +type IGuildTechBuyFields = IGuildTechStartFields; + interface IGuildTechContributeFields { ResearchId: ""; RecipeType: string; diff --git a/src/controllers/api/infestedFoundryController.ts b/src/controllers/api/infestedFoundryController.ts index a01ae16b..40a95d37 100644 --- a/src/controllers/api/infestedFoundryController.ts +++ b/src/controllers/api/infestedFoundryController.ts @@ -3,15 +3,12 @@ import { getAccountIdForRequest } from "@/src/services/loginService"; import { getJSONfromString } from "@/src/helpers/stringHelpers"; import { getInventory, addMiscItems, updateCurrency, addRecipes } from "@/src/services/inventoryService"; import { IOid } from "@/src/types/commonTypes"; -import { - IConsumedSuit, - IInfestedFoundry, - IInventoryDatabaseDocument, - IMiscItem, - ITypeCount -} from "@/src/types/inventoryTypes/inventoryTypes"; +import { IConsumedSuit, IInfestedFoundry, IMiscItem, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes"; import { ExportMisc, ExportRecipes } from "warframe-public-export-plus"; import { getRecipe } from "@/src/services/itemDataService"; +import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel"; +import { toMongoDate } from "@/src/helpers/inventoryHelpers"; +import { logger } from "@/src/utils/logger"; export const infestedFoundryController: RequestHandler = async (req, res) => { const accountId = await getAccountIdForRequest(req); @@ -44,6 +41,25 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { break; } + case "x": { + // shard removal + const request = getJSONfromString(String(req.body)) as IShardUninstallRequest; + const inventory = await getInventory(accountId); + const suit = inventory.Suits.find(suit => suit._id.toString() == request.SuitId.$oid)!; + suit.ArchonCrystalUpgrades![request.Slot] = {}; + const bile = inventory.InfestedFoundry!.Resources!.find( + x => x.ItemType == "/Lotus/Types/Items/InfestedFoundry/HelminthBile" + )!; + bile.Count -= 300; + await inventory.save(); + res.json({ + InventoryChanges: { + InfestedFoundry: inventory.toJSON().InfestedFoundry + } + }); + break; + } + case "n": { // name the beast const request = getJSONfromString(String(req.body)) as IHelminthNameRequest; @@ -71,21 +87,43 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { const miscItemChanges: IMiscItem[] = []; let totalPercentagePointsGained = 0; + const currentUnixSeconds = Math.trunc(new Date().getTime() / 1000); + for (const contribution of request.ResourceContributions) { const snack = ExportMisc.helminthSnacks[contribution.ItemType]; - // Note: Currently ignoring loss of apetite - totalPercentagePointsGained += snack.gain / 0.01; - const resource = inventory.InfestedFoundry.Resources.find(x => x.ItemType == snack.type); - if (resource) { - resource.Count += Math.trunc(snack.gain * 1000); - } else { - inventory.InfestedFoundry.Resources.push({ - ItemType: snack.type, - Count: Math.trunc(snack.gain * 1000) - }); + let resource = inventory.InfestedFoundry.Resources.find(x => x.ItemType == snack.type); + if (!resource) { + resource = + inventory.InfestedFoundry.Resources[ + inventory.InfestedFoundry.Resources.push({ ItemType: snack.type, Count: 0 }) - 1 + ]; } + resource.RecentlyConvertedResources ??= []; + let record = resource.RecentlyConvertedResources.find(x => x.ItemType == contribution.ItemType); + if (!record) { + record = + resource.RecentlyConvertedResources[ + resource.RecentlyConvertedResources.push({ ItemType: contribution.ItemType, Date: 0 }) - 1 + ]; + } + + const hoursRemaining = (record.Date - currentUnixSeconds) / 3600; + const apetiteFactor = apetiteModel(hoursRemaining) / 30; + logger.debug(`helminth eating ${contribution.ItemType} (+${(snack.gain * 100).toFixed(0)}%)`, { + hoursRemaining, + apetiteFactor + }); + if (hoursRemaining >= 18) { + record.Date = currentUnixSeconds + 72 * 60 * 60; + } else { + record.Date = currentUnixSeconds + 24 * 60 * 60; + } + + totalPercentagePointsGained += snack.gain * 100 * apetiteFactor; // 30% would be gain=0.3, so percentage points is equal to gain * 100. + resource.Count += Math.trunc(snack.gain * 1000 * apetiteFactor); // 30% would be gain=0.3 or Count=300, so Count=gain*1000. + // tally items for removal const change = miscItemChanges.find(x => x.ItemType == contribution.ItemType); if (change) { @@ -95,27 +133,43 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { } } - addInfestedFoundryXP(inventory.InfestedFoundry, 666 * totalPercentagePointsGained); + const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry, 666 * totalPercentagePointsGained); + addRecipes(inventory, recipeChanges); addMiscItems(inventory, miscItemChanges); await inventory.save(); res.json({ InventoryChanges: { + Recipes: recipeChanges, InfestedFoundry: { XP: inventory.InfestedFoundry.XP, Resources: inventory.InfestedFoundry.Resources, Slots: inventory.InfestedFoundry.Slots - } - }, - MiscItems: miscItemChanges + }, + MiscItems: miscItemChanges + } }); break; } - case "o": // offerings update - // {"OfferingsIndex":540,"SuitTypes":["/Lotus/Powersuits/PaxDuviricus/PaxDuviricusBaseSuit","/Lotus/Powersuits/Nezha/NezhaBaseSuit","/Lotus/Powersuits/Devourer/DevourerBaseSuit"],"Extra":false} - res.status(404).end(); + case "o": { + // offerings update + const request = getJSONfromString(String(req.body)) as IHelminthOfferingsUpdate; + const inventory = await getInventory(accountId); + inventory.InfestedFoundry ??= {}; + inventory.InfestedFoundry.InvigorationIndex = request.OfferingsIndex; + inventory.InfestedFoundry.InvigorationSuitOfferings = request.SuitTypes; + if (request.Extra) { + inventory.InfestedFoundry.InvigorationsApplied = 0; + } + await inventory.save(); + res.json({ + InventoryChanges: { + InfestedFoundry: inventory.toJSON().InfestedFoundry + } + }); break; + } case "a": { // subsume warframe @@ -134,18 +188,21 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { if (suit.Configs && suit.Configs[0] && suit.Configs[0].pricol) { consumedSuit.c = suit.Configs[0].pricol; } - inventory.InfestedFoundry!.Slots!--; + if ((inventory.InfestedFoundry!.XP ?? 0) < 73125_00) { + inventory.InfestedFoundry!.Slots!--; + } inventory.InfestedFoundry!.ConsumedSuits ??= []; inventory.InfestedFoundry!.ConsumedSuits?.push(consumedSuit); inventory.InfestedFoundry!.LastConsumedSuit = suit; inventory.InfestedFoundry!.AbilityOverrideUnlockCooldown = new Date( new Date().getTime() + 24 * 60 * 60 * 1000 ); - addInfestedFoundryXP(inventory.InfestedFoundry!, 1600_00); + const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, 1600_00); + addRecipes(inventory, recipeChanges); await inventory.save(); - console.log(inventory.toJSON().InfestedFoundry); res.json({ InventoryChanges: { + Recipes: recipeChanges, RemovedIdItems: [ { ItemId: request.SuitId @@ -178,6 +235,52 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { break; } + case "u": { + const request = getJSONfromString(String(req.body)) as IHelminthInvigorationRequest; + const inventory = await getInventory(accountId); + const suit = inventory.Suits.find(x => x._id.toString() == request.SuitId.$oid)!; + const upgradesExpiry = new Date(new Date().getTime() + 7 * 24 * 60 * 60 * 1000); + suit.OffensiveUpgrade = request.OffensiveUpgradeType; + suit.DefensiveUpgrade = request.DefensiveUpgradeType; + suit.UpgradesExpiry = upgradesExpiry; + const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, 4800_00); + addRecipes(inventory, recipeChanges); + for (let i = 0; i != request.ResourceTypes.length; ++i) { + inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == request.ResourceTypes[i])!.Count -= + request.ResourceCosts[i]; + } + inventory.InfestedFoundry!.InvigorationsApplied ??= 0; + inventory.InfestedFoundry!.InvigorationsApplied += 1; + await inventory.save(); + res.json({ + SuitId: request.SuitId, + OffensiveUpgrade: request.OffensiveUpgradeType, + DefensiveUpgrade: request.DefensiveUpgradeType, + UpgradesExpiry: toMongoDate(upgradesExpiry), + InventoryChanges: { + Recipes: recipeChanges, + InfestedFoundry: inventory.toJSON().InfestedFoundry + } + }); + break; + } + + case "custom_unlockall": { + const inventory = await getInventory(accountId); + inventory.InfestedFoundry ??= {}; + inventory.InfestedFoundry.XP ??= 0; + if (151875_00 > inventory.InfestedFoundry.XP) { + const recipeChanges = addInfestedFoundryXP( + inventory.InfestedFoundry, + 151875_00 - inventory.InfestedFoundry.XP + ); + addRecipes(inventory, recipeChanges); + await inventory.save(); + } + res.end(); + break; + } + default: throw new Error(`unhandled infestedFoundry mode: ${String(req.query.mode)}`); } @@ -190,6 +293,11 @@ interface IShardInstallRequest { Color: string; } +interface IShardUninstallRequest { + SuitId: IOid; + Slot: number; +} + interface IHelminthNameRequest { newName: string; } @@ -216,7 +324,8 @@ const colorToShard: Record = { ACC_PURPLE_MYTHIC: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalVioletMythic" }; -const addInfestedFoundryXP = (infestedFoundry: IInfestedFoundry, delta: number): void => { +export const addInfestedFoundryXP = (infestedFoundry: IInfestedFoundry, delta: number): ITypeCount[] => { + const recipeChanges: ITypeCount[] = []; infestedFoundry.XP ??= 0; const prevXP = infestedFoundry.XP; infestedFoundry.XP += delta; @@ -224,14 +333,69 @@ const addInfestedFoundryXP = (infestedFoundry: IInfestedFoundry, delta: number): infestedFoundry.Slots ??= 0; infestedFoundry.Slots += 3; } + if (prevXP < 5625_00 && infestedFoundry.XP >= 5625_00) { + recipeChanges.push({ + ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthShieldsBlueprint", + ItemCount: 1 + }); + } + if (prevXP < 10125_00 && infestedFoundry.XP >= 10125_00) { + recipeChanges.push({ ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthHackBlueprint", ItemCount: 1 }); + } if (prevXP < 15750_00 && infestedFoundry.XP >= 15750_00) { infestedFoundry.Slots ??= 0; infestedFoundry.Slots += 10; } + if (prevXP < 22500_00 && infestedFoundry.XP >= 22500_00) { + recipeChanges.push({ + ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthAmmoEfficiencyBlueprint", + ItemCount: 1 + }); + } + if (prevXP < 30375_00 && infestedFoundry.XP >= 30375_00) { + recipeChanges.push({ ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthStunBlueprint", ItemCount: 1 }); + } if (prevXP < 39375_00 && infestedFoundry.XP >= 39375_00) { infestedFoundry.Slots ??= 0; infestedFoundry.Slots += 20; } + if (prevXP < 60750_00 && infestedFoundry.XP >= 60750_00) { + recipeChanges.push({ ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthStatusBlueprint", ItemCount: 1 }); + } + if (prevXP < 73125_00 && infestedFoundry.XP >= 73125_00) { + infestedFoundry.Slots = 1; + } + if (prevXP < 86625_00 && infestedFoundry.XP >= 86625_00) { + recipeChanges.push({ + ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthShieldArmorBlueprint", + ItemCount: 1 + }); + } + if (prevXP < 101250_00 && infestedFoundry.XP >= 101250_00) { + recipeChanges.push({ + ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthProcBlockBlueprint", + ItemCount: 1 + }); + } + if (prevXP < 117000_00 && infestedFoundry.XP >= 117000_00) { + recipeChanges.push({ + ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthEnergyShareBlueprint", + ItemCount: 1 + }); + } + if (prevXP < 133875_00 && infestedFoundry.XP >= 133875_00) { + recipeChanges.push({ + ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthMaxStatusBlueprint", + ItemCount: 1 + }); + } + if (prevXP < 151875_00 && infestedFoundry.XP >= 151875_00) { + recipeChanges.push({ + ItemType: "/Lotus/Types/Recipes/AbilityOverrides/HelminthTreasureBlueprint", + ItemCount: 1 + }); + } + return recipeChanges; }; interface IHelminthSubsumeRequest { @@ -239,7 +403,7 @@ interface IHelminthSubsumeRequest { Recipe: string; } -export const handleSubsumeCompletion = (inventory: IInventoryDatabaseDocument): ITypeCount[] => { +export const handleSubsumeCompletion = (inventory: TInventoryDatabaseDocument): ITypeCount[] => { const [recipeType] = Object.entries(ExportRecipes).find( ([_recipeType, recipe]) => recipe.secretIngredientAction == "SIA_WARFRAME_ABILITY" && @@ -256,3 +420,52 @@ export const handleSubsumeCompletion = (inventory: IInventoryDatabaseDocument): addRecipes(inventory, recipeChanges); return recipeChanges; }; + +interface IHelminthOfferingsUpdate { + OfferingsIndex: number; + SuitTypes: string[]; + Extra: boolean; +} + +interface IHelminthInvigorationRequest { + SuitId: IOid; + OffensiveUpgradeType: string; + DefensiveUpgradeType: string; + ResourceTypes: string[]; + ResourceCosts: number[]; +} + +// Hours remaining, percentage points gained (out of 30 total) +// 0, 30 +// 5, 25.8 +// 10, 21.6 +// 12, 20 +// 16, 16.6 +// 17, 15.8 +// 18, 15 +// 20, 15 +// 24, 15 +// 36, 15 +// 40, 13.6 +// 47, 11.3 +// 48, 11 +// 50, 10.3 +// 60, 7 +// 70, 3.6 +// 71, 3.3 +// 72, 3 +const apetiteModel = (x: number): number => { + if (x <= 0) { + return 30; + } + if (x < 18) { + return -0.84 * x + 30; + } + if (x <= 36) { + return 15; + } + if (x < 71.9) { + return -0.3327892 * x + 26.94135; + } + return 3; +}; diff --git a/src/controllers/api/inventoryController.ts b/src/controllers/api/inventoryController.ts index f38fe0ec..949cc11f 100644 --- a/src/controllers/api/inventoryController.ts +++ b/src/controllers/api/inventoryController.ts @@ -1,11 +1,10 @@ import { RequestHandler } from "express"; import { getAccountForRequest } from "@/src/services/loginService"; -import { toInventoryResponse } from "@/src/helpers/inventoryHelpers"; import { Inventory } from "@/src/models/inventoryModels/inventoryModel"; import { config } from "@/src/services/configService"; import allDialogue from "@/static/fixed_responses/allDialogue.json"; import { ILoadoutDatabase } from "@/src/types/saveLoadoutTypes"; -import { IInventoryDatabaseDocument, IShipInventory, equipmentKeys } from "@/src/types/inventoryTypes/inventoryTypes"; +import { IInventoryResponse, IShipInventory, equipmentKeys } from "@/src/types/inventoryTypes/inventoryTypes"; import { IPolarity, ArtifactPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes"; import { ExportCustoms, @@ -18,17 +17,9 @@ import { import { handleSubsumeCompletion } from "./infestedFoundryController"; export const inventoryController: RequestHandler = async (request, response) => { - let account; - try { - account = await getAccountForRequest(request); - } catch (e) { - response.status(400).send("Log-in expired"); - return; - } + const account = await getAccountForRequest(request); - const inventory = await Inventory.findOne({ accountOwnerId: account._id.toString() }) - .populate<{ LoadOutPresets: ILoadoutDatabase }>("LoadOutPresets") - .populate<{ Ships: IShipInventory }>("Ships"); + const inventory = await Inventory.findOne({ accountOwnerId: account._id.toString() }); if (!inventory) { response.status(400).json({ error: "inventory was undefined" }); @@ -41,20 +32,21 @@ export const inventoryController: RequestHandler = async (request, response) => account.LastLoginDay = today; await account.save(); - inventory.DailyAffiliation = 16000; - inventory.DailyAffiliationPvp = 16000; - inventory.DailyAffiliationLibrary = 16000; - inventory.DailyAffiliationCetus = 16000; - inventory.DailyAffiliationQuills = 16000; - inventory.DailyAffiliationSolaris = 16000; - inventory.DailyAffiliationVentkids = 16000; - inventory.DailyAffiliationVox = 16000; - inventory.DailyAffiliationEntrati = 16000; - inventory.DailyAffiliationNecraloid = 16000; - inventory.DailyAffiliationZariman = 16000; - inventory.DailyAffiliationKahl = 16000; - inventory.DailyAffiliationCavia = 16000; - inventory.DailyAffiliationHex = 16000; + inventory.DailyAffiliation = 16000 + inventory.PlayerLevel * 500; + inventory.DailyAffiliationPvp = 16000 + inventory.PlayerLevel * 500; + inventory.DailyAffiliationLibrary = 16000 + inventory.PlayerLevel * 500; + inventory.DailyAffiliationCetus = 16000 + inventory.PlayerLevel * 500; + inventory.DailyAffiliationQuills = 16000 + inventory.PlayerLevel * 500; + inventory.DailyAffiliationSolaris = 16000 + inventory.PlayerLevel * 500; + inventory.DailyAffiliationVentkids = 16000 + inventory.PlayerLevel * 500; + inventory.DailyAffiliationVox = 16000 + inventory.PlayerLevel * 500; + inventory.DailyAffiliationEntrati = 16000 + inventory.PlayerLevel * 500; + inventory.DailyAffiliationNecraloid = 16000 + inventory.PlayerLevel * 500; + inventory.DailyAffiliationZariman = 16000 + inventory.PlayerLevel * 500; + inventory.DailyAffiliationKahl = 16000 + inventory.PlayerLevel * 500; + inventory.DailyAffiliationCavia = 16000 + inventory.PlayerLevel * 500; + inventory.DailyAffiliationHex = 16000 + inventory.PlayerLevel * 500; + inventory.DailyFocus = 250000 + inventory.PlayerLevel * 5000; await inventory.save(); } @@ -63,14 +55,17 @@ export const inventoryController: RequestHandler = async (request, response) => inventory.InfestedFoundry.AbilityOverrideUnlockCooldown && new Date() >= inventory.InfestedFoundry.AbilityOverrideUnlockCooldown ) { - handleSubsumeCompletion(inventory as unknown as IInventoryDatabaseDocument); + handleSubsumeCompletion(inventory); await inventory.save(); } - //TODO: make a function that converts from database representation to client - const inventoryJSON = inventory.toJSON(); - - const inventoryResponse = toInventoryResponse(inventoryJSON); + const inventoryWithLoadOutPresets = await inventory.populate<{ LoadOutPresets: ILoadoutDatabase }>( + "LoadOutPresets" + ); + const inventoryWithLoadOutPresetsAndShips = await inventoryWithLoadOutPresets.populate<{ Ships: IShipInventory }>( + "Ships" + ); + const inventoryResponse = inventoryWithLoadOutPresetsAndShips.toJSON(); if (config.infiniteCredits) { inventoryResponse.RegularCredits = 999999999; diff --git a/src/controllers/api/inventorySlotsController.ts b/src/controllers/api/inventorySlotsController.ts index 0c95c89d..cb49ddb4 100644 --- a/src/controllers/api/inventorySlotsController.ts +++ b/src/controllers/api/inventorySlotsController.ts @@ -1,5 +1,5 @@ import { getAccountIdForRequest } from "@/src/services/loginService"; -import { updateCurrencyByAccountId } from "@/src/services/inventoryService"; +import { getInventory, updateCurrency } from "@/src/services/inventoryService"; import { RequestHandler } from "express"; import { updateSlots } from "@/src/services/inventoryService"; import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes"; @@ -26,8 +26,10 @@ export const inventorySlotsController: RequestHandler = async (req, res) => { //TODO: check which slot was purchased because pvpBonus is also possible - const currencyChanges = await updateCurrencyByAccountId(20, true, accountId); - await updateSlots(accountId, InventorySlot.PVE_LOADOUTS, 1, 1); + const inventory = await getInventory(accountId); + const currencyChanges = updateCurrency(inventory, 20, true); + updateSlots(inventory, InventorySlot.PVE_LOADOUTS, 1, 1); + await inventory.save(); //console.log({ InventoryChanges: currencyChanges }, " added loadout changes:"); diff --git a/src/controllers/api/modularWeaponCraftingController.ts b/src/controllers/api/modularWeaponCraftingController.ts index 8d2f83d9..3eb27310 100644 --- a/src/controllers/api/modularWeaponCraftingController.ts +++ b/src/controllers/api/modularWeaponCraftingController.ts @@ -34,9 +34,10 @@ export const modularWeaponCraftingController: RequestHandler = async (req, res) throw new Error(`unknown modular weapon type: ${data.WeaponType}`); } const category = modularWeaponTypes[data.WeaponType]; + const inventory = await getInventory(accountId); // Give weapon - const weapon = await addEquipment(category, data.WeaponType, accountId, data.Parts); + const weapon = addEquipment(inventory, category, data.WeaponType, data.Parts); // Remove credits & parts const miscItemChanges = []; @@ -46,7 +47,6 @@ export const modularWeaponCraftingController: RequestHandler = async (req, res) ItemCount: -1 }); } - const inventory = await getInventory(accountId); const currencyChanges = updateCurrency( inventory, category == "Hoverboards" || category == "MoaPets" ? 5000 : 4000, diff --git a/src/controllers/api/startRecipeController.ts b/src/controllers/api/startRecipeController.ts index 20693509..83501874 100644 --- a/src/controllers/api/startRecipeController.ts +++ b/src/controllers/api/startRecipeController.ts @@ -22,7 +22,6 @@ export const startRecipeController: RequestHandler = async (req, res) => { const recipe = getRecipe(recipeName); if (!recipe) { - logger.error(`unknown recipe ${recipeName}`); throw new Error(`unknown recipe ${recipeName}`); } diff --git a/src/controllers/api/upgradesController.ts b/src/controllers/api/upgradesController.ts index e21d54d0..eea06d2e 100644 --- a/src/controllers/api/upgradesController.ts +++ b/src/controllers/api/upgradesController.ts @@ -8,13 +8,16 @@ import { } from "@/src/types/inventoryTypes/commonInventoryTypes"; import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes"; import { getAccountIdForRequest } from "@/src/services/loginService"; -import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService"; +import { addMiscItems, addRecipes, getInventory, updateCurrency } from "@/src/services/inventoryService"; import { getRecipeByResult } from "@/src/services/itemDataService"; +import { IInventoryChanges } from "@/src/types/purchaseTypes"; +import { addInfestedFoundryXP } from "./infestedFoundryController"; export const upgradesController: RequestHandler = async (req, res) => { const accountId = await getAccountIdForRequest(req); const payload = JSON.parse(String(req.body)) as IUpgradesRequest; const inventory = await getInventory(accountId); + const inventoryChanges: IInventoryChanges = {}; for (const operation of payload.Operations) { if ( operation.UpgradeRequirement == "/Lotus/Types/Items/MiscItems/ModSlotUnlocker" || @@ -35,6 +38,7 @@ export const upgradesController: RequestHandler = async (req, res) => { const suit = inventory.Suits.find(x => x._id.toString() == payload.ItemId.$oid)!; let newAbilityOverride: IAbilityOverride | undefined; + let totalPercentagePointsConsumed = 0; if (operation.UpgradeRequirement != "") { newAbilityOverride = { Ability: operation.UpgradeRequirement, @@ -43,6 +47,7 @@ export const upgradesController: RequestHandler = async (req, res) => { const recipe = getRecipeByResult(operation.UpgradeRequirement)!; for (const ingredient of recipe.ingredients) { + totalPercentagePointsConsumed += ingredient.ItemCount / 10; inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType)!.Count -= ingredient.ItemCount; } @@ -52,6 +57,12 @@ export const upgradesController: RequestHandler = async (req, res) => { suit.Configs[entry.Slot] ??= {}; suit.Configs[entry.Slot].AbilityOverride = newAbilityOverride; } + + const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, totalPercentagePointsConsumed * 8); + addRecipes(inventory, recipeChanges); + + inventoryChanges.Recipes = recipeChanges; + inventoryChanges.InfestedFoundry = inventory.toJSON().InfestedFoundry; } else switch (operation.UpgradeRequirement) { case "/Lotus/Types/Items/MiscItems/OrokinReactor": @@ -146,7 +157,7 @@ export const upgradesController: RequestHandler = async (req, res) => { } } await inventory.save(); - res.json({ InventoryChanges: {} }); + res.json({ InventoryChanges: inventoryChanges }); }; const setSlotPolarity = (item: IEquipmentDatabase, slot: number, polarity: ArtifactPolarity): void => { diff --git a/src/controllers/custom/addItemController.ts b/src/controllers/custom/addItemController.ts index c1045e63..a045739c 100644 --- a/src/controllers/custom/addItemController.ts +++ b/src/controllers/custom/addItemController.ts @@ -1,7 +1,7 @@ import { getAccountIdForRequest } from "@/src/services/loginService"; import { ItemType, toAddItemRequest } from "@/src/helpers/customHelpers/addItemHelpers"; import { getWeaponType } from "@/src/services/itemDataService"; -import { addPowerSuit, addEquipment } from "@/src/services/inventoryService"; +import { addPowerSuit, addEquipment, getInventory } from "@/src/services/inventoryService"; import { RequestHandler } from "express"; const addItemController: RequestHandler = async (req, res) => { @@ -10,14 +10,18 @@ const addItemController: RequestHandler = async (req, res) => { switch (request.type) { case ItemType.Powersuit: { - const powersuit = await addPowerSuit(request.InternalName, accountId); - res.json(powersuit); + const inventory = await getInventory(accountId); + const inventoryChanges = addPowerSuit(inventory, request.InternalName); + await inventory.save(); + res.json(inventoryChanges); return; } case ItemType.Weapon: { + const inventory = await getInventory(accountId); const weaponType = getWeaponType(request.InternalName); - const weapon = await addEquipment(weaponType, request.InternalName, accountId); - res.json(weapon); + const inventoryChanges = addEquipment(inventory, weaponType, request.InternalName); + await inventory.save(); + res.json(inventoryChanges); break; } default: diff --git a/src/controllers/custom/getItemListsController.ts b/src/controllers/custom/getItemListsController.ts index 72fb05da..9a37fa14 100644 --- a/src/controllers/custom/getItemListsController.ts +++ b/src/controllers/custom/getItemListsController.ts @@ -37,9 +37,20 @@ const getItemListsController: RequestHandler = (req, res) => { } } for (const [uniqueName, item] of Object.entries(ExportResources)) { + let name = getString(item.name, lang); + if ("dissectionParts" in item) { + name = getString("/Lotus/Language/Fish/FishDisplayName", lang).split("|FISH_NAME|").join(name); + if (uniqueName.indexOf("Large") != -1) { + name = name.split("|FISH_SIZE|").join(getString("/Lotus/Language/Fish/FishSizeLargeAbbrev", lang)); + } else if (uniqueName.indexOf("Medium") != -1) { + name = name.split("|FISH_SIZE|").join(getString("/Lotus/Language/Fish/FishSizeMediumAbbrev", lang)); + } else { + name = name.split("|FISH_SIZE|").join(getString("/Lotus/Language/Fish/FishSizeSmallAbbrev", lang)); + } + } miscitems.push({ uniqueName: item.productCategory + ":" + uniqueName, - name: getString(item.name, lang) + name: name }); } for (const [uniqueName, item] of Object.entries(ExportGear)) { diff --git a/src/controllers/pay/getSkuCatalogController.ts b/src/controllers/pay/getSkuCatalogController.ts new file mode 100644 index 00000000..baf79d58 --- /dev/null +++ b/src/controllers/pay/getSkuCatalogController.ts @@ -0,0 +1,5 @@ +import { RequestHandler } from "express"; + +export const getSkuCatalogController: RequestHandler = (_req, res) => { + res.sendFile("static/fixed_responses/getSkuCatalog.json", { root: "./" }); +}; diff --git a/src/controllers/misc/steamPacksController.ts b/src/controllers/pay/steamPacksController.ts similarity index 100% rename from src/controllers/misc/steamPacksController.ts rename to src/controllers/pay/steamPacksController.ts diff --git a/src/helpers/inventoryHelpers.ts b/src/helpers/inventoryHelpers.ts index d85fc978..d7fa7b25 100644 --- a/src/helpers/inventoryHelpers.ts +++ b/src/helpers/inventoryHelpers.ts @@ -1,14 +1,6 @@ import { IMongoDate, IOid } from "@/src/types/commonTypes"; -import { IInventoryResponse } from "@/src/types/inventoryTypes/inventoryTypes"; import { Types } from "mongoose"; -//TODO: this needs to be addressed: a schema's toJSON is responsible for changing Oid and Date to their corresponding Response versions __id to "ItemId":{"$oid":"6450f720bc562ebf030222d4"}, and a Date to "date":{"$date":{"$numberLong":"unix timestamp"}) -export const toInventoryResponse = (inventoryDatabase: { accountOwnerId: Types.ObjectId }): IInventoryResponse => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { accountOwnerId, ...inventoryResponse } = inventoryDatabase; - return inventoryResponse as unknown as IInventoryResponse; -}; - export const toOid = (objectId: Types.ObjectId): IOid => { return { $oid: objectId.toString() } satisfies IOid; }; diff --git a/src/middleware/errorHandler.ts b/src/middleware/errorHandler.ts new file mode 100644 index 00000000..45f69062 --- /dev/null +++ b/src/middleware/errorHandler.ts @@ -0,0 +1,16 @@ +import { NextFunction, Request, Response } from "express"; +import { logger } from "../utils/logger"; + +export const errorHandler = (err: Error, req: Request, res: Response, _next: NextFunction): void => { + if (err.message == "Invalid accountId-nonce pair") { + res.status(400).send("Log-in expired"); + } else if (err.stack) { + const stackArr = err.stack.split("\n"); + stackArr[0] += ` while processing ${req.path} request`; + logger.error(stackArr.join("\n")); + res.status(500).end(); + } else { + logger.error(`uncaught error while processing ${req.path} request: ${err.message}`); + res.status(500).end(); + } +}; diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index 37a674c2..8202bda9 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -1,4 +1,4 @@ -import { Model, Schema, Types, model } from "mongoose"; +import { Document, Model, Schema, Types, model } from "mongoose"; import { IFlavourItem, IRawUpgrade, @@ -45,7 +45,8 @@ import { ICrewShipMembers, ICrewShip, ICrewShipPilotWeapon, - IShipExterior + IShipExterior, + IHelminthFoodRecord } from "../../types/inventoryTypes/inventoryTypes"; import { IOid } from "../../types/commonTypes"; import { @@ -233,6 +234,9 @@ const EquipmentSchema = new Schema( UnlockLevel: Number, Expiry: Date, SkillTree: String, + OffensiveUpgrade: String, + DefensiveUpgrade: String, + UpgradesExpiry: Date, ArchonCrystalUpgrades: { type: [ArchonCrystalUpgradeSchema], default: undefined } }, { id: false } @@ -467,7 +471,22 @@ const consumedSchuitsSchema = new Schema( { _id: false } ); -const helminthResourceSchema = new Schema({ ItemType: String, Count: Number }, { _id: false }); +const helminthFoodRecordSchema = new Schema( + { + ItemType: String, + Date: Number + }, + { _id: false } +); + +const helminthResourceSchema = new Schema( + { + ItemType: String, + Count: Number, + RecentlyConvertedResources: { type: [helminthFoodRecordSchema], default: undefined } + }, + { _id: false } +); const infestedFoundrySchema = new Schema( { @@ -1061,6 +1080,7 @@ inventorySchema.set("toJSON", { transform(_document, returnedObject) { delete returnedObject._id; delete returnedObject.__v; + delete returnedObject.accountOwnerId; const inventoryDatabase = returnedObject as IInventoryDatabase; const inventoryResponse = returnedObject as IInventoryResponse; @@ -1114,3 +1134,15 @@ type InventoryDocumentProps = { type InventoryModelType = Model; export const Inventory = model("Inventory", inventorySchema); + +// eslint-disable-next-line @typescript-eslint/ban-types +export type TInventoryDatabaseDocument = Document & + Omit< + IInventoryDatabase & { + _id: Types.ObjectId; + } & { + __v: number; + }, + keyof InventoryDocumentProps + > & + InventoryDocumentProps; diff --git a/src/routes/api.ts b/src/routes/api.ts index 0a94e506..4194f44c 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -5,6 +5,7 @@ import { artifactsController } from "../controllers/api/artifactsController"; import { checkDailyMissionBonusController } from "@/src/controllers/api/checkDailyMissionBonusController"; import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController"; import { createGuildController } from "@/src/controllers/api/createGuildController"; +import { creditsController } from "@/src/controllers/api/creditsController"; import { deleteSessionController } from "@/src/controllers/api/deleteSessionController"; import { dojoController } from "@/src/controllers/api/dojoController"; import { dronesController } from "@/src/controllers/api/dronesController"; @@ -16,7 +17,6 @@ import { focusController } from "@/src/controllers/api/focusController"; import { fusionTreasuresController } from "@/src/controllers/api/fusionTreasuresController"; import { genericUpdateController } from "@/src/controllers/api/genericUpdateController"; import { getAllianceController } from "@/src/controllers/api/getAllianceController"; -import { getCreditsController } from "@/src/controllers/api/getCreditsController"; import { getDailyDealStockLevelsController } from "@/src/controllers/api/getDailyDealStockLevelsController"; import { getFriendsController } from "@/src/controllers/api/getFriendsController"; import { getGuildController } from "@/src/controllers/api/getGuildController"; @@ -76,7 +76,7 @@ const apiRouter = express.Router(); // get apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController); -apiRouter.get("/credits.php", getCreditsController); +apiRouter.get("/credits.php", creditsController); apiRouter.get("/deleteSession.php", deleteSessionController); apiRouter.get("/dojo", dojoController); apiRouter.get("/drones.php", dronesController); diff --git a/src/routes/pay.ts b/src/routes/pay.ts new file mode 100644 index 00000000..1a8af754 --- /dev/null +++ b/src/routes/pay.ts @@ -0,0 +1,11 @@ +import express from "express"; + +import { getSkuCatalogController } from "@/src/controllers/pay/getSkuCatalogController"; +import { steamPacksController } from "@/src/controllers/pay/steamPacksController"; + +const payRouter = express.Router(); + +payRouter.get("/getSkuCatalog.php", getSkuCatalogController); +payRouter.post("/steamPacks.php", steamPacksController); + +export { payRouter }; diff --git a/src/services/guildService.ts b/src/services/guildService.ts index dda01ef8..1fcddad4 100644 --- a/src/services/guildService.ts +++ b/src/services/guildService.ts @@ -2,7 +2,7 @@ import { Request } from "express"; import { getAccountIdForRequest } from "@/src/services/loginService"; import { getInventory } from "@/src/services/inventoryService"; import { Guild } from "@/src/models/guildModel"; -import { IInventoryDatabaseDocument } from "../types/inventoryTypes/inventoryTypes"; +import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel"; export const getGuildForRequest = async (req: Request) => { const accountId = await getAccountIdForRequest(req); @@ -10,7 +10,7 @@ export const getGuildForRequest = async (req: Request) => { return await getGuildForRequestEx(req, inventory); }; -export const getGuildForRequestEx = async (req: Request, inventory: IInventoryDatabaseDocument) => { +export const getGuildForRequestEx = async (req: Request, inventory: TInventoryDatabaseDocument) => { const guildId = req.query.guildId as string; if (!inventory.GuildId || inventory.GuildId.toString() != guildId) { throw new Error("Account is not in the guild that it has sent a request for"); diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 1265e802..652fcaf3 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -1,4 +1,4 @@ -import { Inventory } from "@/src/models/inventoryModels/inventoryModel"; +import { Inventory, TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel"; import postTutorialInventory from "@/static/fixed_responses/postTutorialInventory.json"; import { config } from "@/src/services/configService"; import { Types } from "mongoose"; @@ -7,7 +7,6 @@ import { IChallengeProgress, IConsumable, IFlavourItem, - IInventoryDatabaseDocument, IMiscItem, IMission, IRawUpgrade, @@ -80,8 +79,9 @@ export const combineInventoryChanges = (InventoryChanges: IInventoryChanges, del } } else if (typeof delta[key] == "object") { console.assert(key.substring(-3) == "Bin"); + console.assert(key != "InfestedFoundry"); const left = InventoryChanges[key] as IBinChanges; - const right: IBinChanges = delta[key]; + const right = delta[key] as IBinChanges; left.count += right.count; left.platinum += right.platinum; left.Slots += right.Slots; @@ -95,7 +95,7 @@ export const combineInventoryChanges = (InventoryChanges: IInventoryChanges, del } }; -export const getInventory = async (accountOwnerId: string) => { +export const getInventory = async (accountOwnerId: string): Promise => { const inventory = await Inventory.findOne({ accountOwnerId: accountOwnerId }); if (!inventory) { @@ -106,13 +106,12 @@ export const getInventory = async (accountOwnerId: string) => { }; export const addItem = async ( - accountId: string, + inventory: TInventoryDatabaseDocument, typeName: string, quantity: number = 1 ): Promise<{ InventoryChanges: IInventoryChanges }> => { // Strict typing if (typeName in ExportRecipes) { - const inventory = await getInventory(accountId); const recipeChanges = [ { ItemType: typeName, @@ -120,7 +119,6 @@ export const addItem = async ( } satisfies ITypeCount ]; addRecipes(inventory, recipeChanges); - await inventory.save(); return { InventoryChanges: { Recipes: recipeChanges @@ -128,11 +126,9 @@ export const addItem = async ( }; } if (typeName in ExportResources) { - const inventory = await getInventory(accountId); if (ExportResources[typeName].productCategory == "Ships") { - const oid = await createShip(new Types.ObjectId(accountId), typeName); + const oid = await createShip(inventory.accountOwnerId, typeName); inventory.Ships.push(oid); - await inventory.save(); return { InventoryChanges: { Ships: [ @@ -144,11 +140,8 @@ export const addItem = async ( } }; } else if (ExportResources[typeName].productCategory == "CrewShips") { - return { - InventoryChanges: { - CrewShips: [await addCrewShip(typeName, accountId)] - } - }; + const inventoryChanges = addCrewShip(inventory, typeName); + return { InventoryChanges: inventoryChanges }; } else { const miscItemChanges = [ { @@ -157,7 +150,6 @@ export const addItem = async ( } satisfies IMiscItem ]; addMiscItems(inventory, miscItemChanges); - await inventory.save(); return { InventoryChanges: { MiscItems: miscItemChanges @@ -166,21 +158,14 @@ export const addItem = async ( } } if (typeName in ExportCustoms) { - return { - InventoryChanges: { - WeaponSkins: [await addSkin(typeName, accountId)] - } - }; + const inventoryChanges = addSkin(inventory, typeName); + return { InventoryChanges: inventoryChanges }; } if (typeName in ExportFlavour) { - return { - InventoryChanges: { - FlavourItems: [await addCustomization(typeName, accountId)] - } - }; + const inventoryChanges = addCustomization(inventory, typeName); + return { InventoryChanges: inventoryChanges }; } if (typeName in ExportUpgrades || typeName in ExportArcanes) { - const inventory = await getInventory(accountId); const changes = [ { ItemType: typeName, @@ -188,7 +173,6 @@ export const addItem = async ( } ]; addMods(inventory, changes); - await inventory.save(); return { InventoryChanges: { RawUpgrades: changes @@ -196,7 +180,6 @@ export const addItem = async ( }; } if (typeName in ExportGear) { - const inventory = await getInventory(accountId); const consumablesChanges = [ { ItemType: typeName, @@ -204,7 +187,6 @@ export const addItem = async ( } satisfies IConsumable ]; addConsumables(inventory, consumablesChanges); - await inventory.save(); return { InventoryChanges: { Consumables: consumablesChanges @@ -217,8 +199,8 @@ export const addItem = async ( case "Powersuits": switch (typeName.substr(1).split("/")[2]) { default: { - const inventoryChanges = await addPowerSuit(typeName, accountId); - await updateSlots(accountId, InventorySlot.SUITS, 0, 1); + const inventoryChanges = addPowerSuit(inventory, typeName); + updateSlots(inventory, InventorySlot.SUITS, 0, 1); return { InventoryChanges: { ...inventoryChanges, @@ -231,22 +213,22 @@ export const addItem = async ( }; } case "Archwing": { - const spaceSuit = await addSpaceSuit(typeName, accountId); - await updateSlots(accountId, InventorySlot.SPACESUITS, 0, 1); + const inventoryChanges = addSpaceSuit(inventory, typeName); + updateSlots(inventory, InventorySlot.SPACESUITS, 0, 1); return { InventoryChanges: { + ...inventoryChanges, SpaceSuitBin: { count: 1, platinum: 0, Slots: -1 - }, - SpaceSuits: [spaceSuit] + } } }; } case "EntratiMech": { - const inventoryChanges = await addMechSuit(typeName, accountId); - await updateSlots(accountId, InventorySlot.MECHSUITS, 0, 1); + const inventoryChanges = addMechSuit(inventory, typeName); + updateSlots(inventory, InventorySlot.MECHSUITS, 0, 1); return { InventoryChanges: { ...inventoryChanges, @@ -262,18 +244,17 @@ export const addItem = async ( break; case "Weapons": { const weaponType = getWeaponType(typeName); - const weapon = await addEquipment(weaponType, typeName, accountId); - await updateSlots(accountId, InventorySlot.WEAPONS, 0, 1); + const inventoryChanges = addEquipment(inventory, weaponType, typeName); + updateSlots(inventory, InventorySlot.WEAPONS, 0, 1); return { InventoryChanges: { - WeaponBin: { count: 1, platinum: 0, Slots: -1 }, - [weaponType]: [weapon] + ...inventoryChanges, + WeaponBin: { count: 1, platinum: 0, Slots: -1 } } }; } case "Objects": { // /Lotus/Objects/Tenno/Props/TnoLisetTextProjector (Note Beacon) - const inventory = await getInventory(accountId); const changes = [ { ItemType: typeName, @@ -281,7 +262,6 @@ export const addItem = async ( } satisfies IMiscItem ]; addShipDecorations(inventory, changes); - await inventory.save(); return { InventoryChanges: { ShipDecorations: changes @@ -291,8 +271,8 @@ export const addItem = async ( case "Types": switch (typeName.substr(1).split("/")[2]) { case "Sentinels": { - const inventoryChanges = await addSentinel(typeName, accountId); - await updateSlots(accountId, InventorySlot.SENTINELS, 0, 1); + const inventoryChanges = addSentinel(inventory, typeName); + updateSlots(inventory, InventorySlot.SENTINELS, 0, 1); return { InventoryChanges: { ...inventoryChanges, @@ -303,7 +283,6 @@ export const addItem = async ( case "Items": { switch (typeName.substr(1).split("/")[3]) { case "ShipDecos": { - const inventory = await getInventory(accountId); const changes = [ { ItemType: typeName, @@ -311,7 +290,6 @@ export const addItem = async ( } satisfies IMiscItem ]; addShipDecorations(inventory, changes); - await inventory.save(); return { InventoryChanges: { ShipDecorations: changes @@ -319,7 +297,6 @@ export const addItem = async ( }; } default: { - const inventory = await getInventory(accountId); const miscItemChanges = [ { ItemType: typeName, @@ -327,7 +304,6 @@ export const addItem = async ( } satisfies IMiscItem ]; addMiscItems(inventory, miscItemChanges); - await inventory.save(); return { InventoryChanges: { MiscItems: miscItemChanges @@ -339,7 +315,6 @@ export const addItem = async ( case "Game": if (typeName.substr(1).split("/")[3] == "Projections") { // Void Relics, e.g. /Lotus/Types/Game/Projections/T2VoidProjectionGaussPrimeDBronze - const inventory = await getInventory(accountId); const miscItemChanges = [ { ItemType: typeName, @@ -347,7 +322,6 @@ export const addItem = async ( } satisfies IMiscItem ]; addMiscItems(inventory, miscItemChanges); - await inventory.save(); return { InventoryChanges: { MiscItems: miscItemChanges @@ -364,13 +338,13 @@ export const addItem = async ( }; //TODO: maybe genericMethod for all the add methods, they share a lot of logic -export const addSentinel = async (sentinelName: string, accountId: string): Promise => { - const inventoryChanges: IInventoryChanges = {}; - +export const addSentinel = ( + inventory: TInventoryDatabaseDocument, + sentinelName: string, + inventoryChanges: IInventoryChanges = {} +): IInventoryChanges => { if (ExportSentinels[sentinelName]?.defaultWeapon) { - inventoryChanges.SentinelWeapons = [ - await addSentinelWeapon(ExportSentinels[sentinelName].defaultWeapon, accountId) - ]; + addSentinelWeapon(inventory, ExportSentinels[sentinelName].defaultWeapon, inventoryChanges); } const modsToGive: IRawUpgrade[] = []; @@ -388,96 +362,109 @@ export const addSentinel = async (sentinelName: string, accountId: string): Prom } } - const inventory = await getInventory(accountId); addMods(inventory, modsToGive); - const sentinelIndex = inventory.Sentinels.push({ ItemType: sentinelName, Configs: configs, XP: 0 }); - const changedInventory = await inventory.save(); - inventoryChanges.Sentinels = [changedInventory.Sentinels[sentinelIndex - 1].toJSON()]; + const sentinelIndex = inventory.Sentinels.push({ ItemType: sentinelName, Configs: configs, XP: 0 }) - 1; + inventoryChanges.Sentinels ??= []; + (inventoryChanges.Sentinels as IEquipmentClient[]).push( + inventory.Sentinels[sentinelIndex].toJSON() + ); return inventoryChanges; }; -export const addSentinelWeapon = async (typeName: string, accountId: string): Promise => { - const inventory = await getInventory(accountId); - const sentinelIndex = inventory.SentinelWeapons.push({ ItemType: typeName }); - const changedInventory = await inventory.save(); - return changedInventory.SentinelWeapons[sentinelIndex - 1].toJSON(); +export const addSentinelWeapon = ( + inventory: TInventoryDatabaseDocument, + typeName: string, + inventoryChanges: IInventoryChanges +): void => { + const index = inventory.SentinelWeapons.push({ ItemType: typeName }) - 1; + inventoryChanges.SentinelWeapons ??= []; + (inventoryChanges.SentinelWeapons as IEquipmentClient[]).push( + inventory.SentinelWeapons[index].toJSON() + ); }; -export const addPowerSuit = async (powersuitName: string, accountId: string): Promise => { - const inventoryChanges: IInventoryChanges = {}; +export const addPowerSuit = ( + inventory: TInventoryDatabaseDocument, + powersuitName: string, + inventoryChanges: IInventoryChanges = {} +): IInventoryChanges => { const specialItems = getExalted(powersuitName); if (specialItems) { - for await (const specialItem of specialItems) { - await addSpecialItem(specialItem, accountId, inventoryChanges); + for (const specialItem of specialItems) { + addSpecialItem(inventory, specialItem, inventoryChanges); } } - const inventory = await getInventory(accountId); - const suitIndex = inventory.Suits.push({ ItemType: powersuitName, Configs: [], UpgradeVer: 101, XP: 0 }); - const changedInventory = await inventory.save(); - inventoryChanges.Suits = [changedInventory.Suits[suitIndex - 1].toJSON()]; + const suitIndex = inventory.Suits.push({ ItemType: powersuitName, Configs: [], UpgradeVer: 101, XP: 0 }) - 1; + inventoryChanges.Suits ??= []; + (inventoryChanges.Suits as IEquipmentClient[]).push(inventory.Suits[suitIndex].toJSON()); return inventoryChanges; }; -export const addMechSuit = async (mechsuitName: string, accountId: string): Promise => { - const inventoryChanges: IInventoryChanges = {}; +export const addMechSuit = ( + inventory: TInventoryDatabaseDocument, + mechsuitName: string, + inventoryChanges: IInventoryChanges = {} +): IInventoryChanges => { const specialItems = getExalted(mechsuitName); if (specialItems) { - for await (const specialItem of specialItems) { - await addSpecialItem(specialItem, accountId, inventoryChanges); + for (const specialItem of specialItems) { + addSpecialItem(inventory, specialItem, inventoryChanges); } } - const inventory = await getInventory(accountId); - const suitIndex = inventory.MechSuits.push({ ItemType: mechsuitName, Configs: [], UpgradeVer: 101, XP: 0 }); - const changedInventory = await inventory.save(); - inventoryChanges.MechSuits = [changedInventory.MechSuits[suitIndex - 1].toJSON()]; + const suitIndex = inventory.MechSuits.push({ ItemType: mechsuitName, Configs: [], UpgradeVer: 101, XP: 0 }) - 1; + inventoryChanges.MechSuits ??= []; + (inventoryChanges.MechSuits as IEquipmentClient[]).push(inventory.MechSuits[suitIndex].toJSON()); return inventoryChanges; }; -export const addSpecialItem = async ( +export const addSpecialItem = ( + inventory: TInventoryDatabaseDocument, itemName: string, - accountId: string, inventoryChanges: IInventoryChanges -): Promise => { - const inventory = await getInventory(accountId); +): void => { if (inventory.SpecialItems.find(x => x.ItemType == itemName)) { return; } - const specialItemIndex = inventory.SpecialItems.push({ - ItemType: itemName, - Configs: [], - Features: 1, - UpgradeVer: 101, - XP: 0 - }); - const changedInventory = await inventory.save(); + const specialItemIndex = + inventory.SpecialItems.push({ + ItemType: itemName, + Configs: [], + Features: 1, + UpgradeVer: 101, + XP: 0 + }) - 1; inventoryChanges.SpecialItems ??= []; - (inventoryChanges.SpecialItems as object[]).push(changedInventory.SpecialItems[specialItemIndex - 1].toJSON()); + (inventoryChanges.SpecialItems as IEquipmentClient[]).push( + inventory.SpecialItems[specialItemIndex].toJSON() + ); }; -export const addSpaceSuit = async (spacesuitName: string, accountId: string): Promise => { - const inventory = await getInventory(accountId); - const suitIndex = inventory.SpaceSuits.push({ ItemType: spacesuitName, Configs: [], UpgradeVer: 101, XP: 0 }); - const changedInventory = await inventory.save(); - return changedInventory.SpaceSuits[suitIndex - 1].toJSON(); +export const addSpaceSuit = ( + inventory: TInventoryDatabaseDocument, + spacesuitName: string, + inventoryChanges: IInventoryChanges = {} +): IInventoryChanges => { + const suitIndex = inventory.SpaceSuits.push({ ItemType: spacesuitName, Configs: [], UpgradeVer: 101, XP: 0 }) - 1; + inventoryChanges.SpaceSuits ??= []; + (inventoryChanges.SpaceSuits as IEquipmentClient[]).push( + inventory.SpaceSuits[suitIndex].toJSON() + ); + return inventoryChanges; }; -export const updateSlots = async ( - accountId: string, +export const updateSlots = ( + inventory: TInventoryDatabaseDocument, slotName: SlotNames, slotAmount: number, extraAmount: number -): Promise => { - const inventory = await getInventory(accountId); - +): void => { inventory[slotName].Slots += slotAmount; if (inventory[slotName].Extra === undefined) { inventory[slotName].Extra = extraAmount; } else { inventory[slotName].Extra += extraAmount; } - - await inventory.save(); }; const isCurrencyTracked = (usePremium: boolean): boolean => { @@ -485,7 +472,7 @@ const isCurrencyTracked = (usePremium: boolean): boolean => { }; export const updateCurrency = ( - inventory: IInventoryDatabaseDocument, + inventory: TInventoryDatabaseDocument, price: number, usePremium: boolean ): ICurrencyChanges => { @@ -549,48 +536,65 @@ export const updateTheme = async (data: IThemeUpdateRequest, accountId: string): await inventory.save(); }; -export const addEquipment = async ( +export const addEquipment = ( + inventory: TInventoryDatabaseDocument, category: TEquipmentKey, type: string, - accountId: string, - modularParts: string[] | undefined = undefined -): Promise => { - const inventory = await getInventory(accountId); + modularParts: string[] | undefined = undefined, + inventoryChanges: IInventoryChanges = {} +): IInventoryChanges => { + const index = + inventory[category].push({ + ItemType: type, + Configs: [], + XP: 0, + ModularParts: modularParts + }) - 1; - const index = inventory[category].push({ - ItemType: type, - Configs: [], - XP: 0, - ModularParts: modularParts - }); - - const changedInventory = await inventory.save(); - return changedInventory[category][index - 1].toJSON() as object as IEquipmentClient; + inventoryChanges[category] ??= []; + (inventoryChanges[category] as IEquipmentClient[]).push(inventory[category][index].toJSON()); + return inventoryChanges; }; -export const addCustomization = async (customizatonName: string, accountId: string): Promise => { - const inventory = await getInventory(accountId); - const flavourItemIndex = inventory.FlavourItems.push({ ItemType: customizatonName }) - 1; - const changedInventory = await inventory.save(); - return changedInventory.FlavourItems[flavourItemIndex].toJSON(); +export const addCustomization = ( + inventory: TInventoryDatabaseDocument, + customizationName: string, + inventoryChanges: IInventoryChanges = {} +): IInventoryChanges => { + const flavourItemIndex = inventory.FlavourItems.push({ ItemType: customizationName }) - 1; + inventoryChanges.FlavourItems ??= []; + (inventoryChanges.FlavourItems as IFlavourItem[]).push( + inventory.FlavourItems[flavourItemIndex].toJSON() + ); + return inventoryChanges; }; -export const addSkin = async (typeName: string, accountId: string): Promise => { - const inventory = await getInventory(accountId); +export const addSkin = ( + inventory: TInventoryDatabaseDocument, + typeName: string, + inventoryChanges: IInventoryChanges = {} +): IInventoryChanges => { const index = inventory.WeaponSkins.push({ ItemType: typeName }) - 1; - const changedInventory = await inventory.save(); - return changedInventory.WeaponSkins[index].toJSON() as object as IWeaponSkinClient; + inventoryChanges.WeaponSkins ??= []; + (inventoryChanges.WeaponSkins as IWeaponSkinClient[]).push( + inventory.WeaponSkins[index].toJSON() + ); + return inventoryChanges; }; -const addCrewShip = async (typeName: string, accountId: string) => { - const inventory = await getInventory(accountId); +const addCrewShip = ( + inventory: TInventoryDatabaseDocument, + typeName: string, + inventoryChanges: IInventoryChanges = {} +): IInventoryChanges => { const index = inventory.CrewShips.push({ ItemType: typeName }) - 1; - const changedInventory = await inventory.save(); - return changedInventory.CrewShips[index].toJSON(); + inventoryChanges.CrewShips ??= []; + (inventoryChanges.CrewShips as object[]).push(inventory.CrewShips[index].toJSON()); + return inventoryChanges; }; const addGearExpByCategory = ( - inventory: IInventoryDatabaseDocument, + inventory: TInventoryDatabaseDocument, gearArray: IEquipmentClient[] | undefined, categoryName: TEquipmentKey ): void => { @@ -622,7 +626,7 @@ const addGearExpByCategory = ( }); }; -export const addMiscItems = (inventory: IInventoryDatabaseDocument, itemsArray: IMiscItem[] | undefined): void => { +export const addMiscItems = (inventory: TInventoryDatabaseDocument, itemsArray: IMiscItem[] | undefined): void => { const { MiscItems } = inventory; itemsArray?.forEach(({ ItemCount, ItemType }) => { @@ -638,7 +642,7 @@ export const addMiscItems = (inventory: IInventoryDatabaseDocument, itemsArray: }; export const addShipDecorations = ( - inventory: IInventoryDatabaseDocument, + inventory: TInventoryDatabaseDocument, itemsArray: IConsumable[] | undefined ): void => { const { ShipDecorations } = inventory; @@ -655,7 +659,7 @@ export const addShipDecorations = ( }); }; -export const addConsumables = (inventory: IInventoryDatabaseDocument, itemsArray: IConsumable[] | undefined): void => { +export const addConsumables = (inventory: TInventoryDatabaseDocument, itemsArray: IConsumable[] | undefined): void => { const { Consumables } = inventory; itemsArray?.forEach(({ ItemCount, ItemType }) => { @@ -670,7 +674,7 @@ export const addConsumables = (inventory: IInventoryDatabaseDocument, itemsArray }); }; -export const addRecipes = (inventory: IInventoryDatabaseDocument, itemsArray: ITypeCount[] | undefined): void => { +export const addRecipes = (inventory: TInventoryDatabaseDocument, itemsArray: ITypeCount[] | undefined): void => { const { Recipes } = inventory; itemsArray?.forEach(({ ItemCount, ItemType }) => { @@ -685,7 +689,7 @@ export const addRecipes = (inventory: IInventoryDatabaseDocument, itemsArray: IT }); }; -export const addMods = (inventory: IInventoryDatabaseDocument, itemsArray: IRawUpgrade[] | undefined): void => { +export const addMods = (inventory: TInventoryDatabaseDocument, itemsArray: IRawUpgrade[] | undefined): void => { const { RawUpgrades } = inventory; itemsArray?.forEach(({ ItemType, ItemCount }) => { const itemIndex = RawUpgrades.findIndex(i => i.ItemType === ItemType); @@ -700,7 +704,7 @@ export const addMods = (inventory: IInventoryDatabaseDocument, itemsArray: IRawU }; export const addFusionTreasures = ( - inventory: IInventoryDatabaseDocument, + inventory: TInventoryDatabaseDocument, itemsArray: IFusionTreasure[] | undefined ): void => { const { FusionTreasures } = inventory; @@ -729,7 +733,7 @@ export const updateChallengeProgress = async ( }; export const addSeasonalChallengeHistory = ( - inventory: IInventoryDatabaseDocument, + inventory: TInventoryDatabaseDocument, itemsArray: ISeasonChallenge[] | undefined ): void => { const category = inventory.SeasonChallengeHistory; @@ -746,7 +750,7 @@ export const addSeasonalChallengeHistory = ( }; export const addChallenges = ( - inventory: IInventoryDatabaseDocument, + inventory: TInventoryDatabaseDocument, itemsArray: IChallengeProgress[] | undefined ): void => { const category = inventory.ChallengeProgress; @@ -763,7 +767,7 @@ export const addChallenges = ( }); }; -const addMissionComplete = (inventory: IInventoryDatabaseDocument, { Tag, Completes }: IMission): void => { +const addMissionComplete = (inventory: TInventoryDatabaseDocument, { Tag, Completes }: IMission): void => { const { Missions } = inventory; const itemIndex = Missions.findIndex(item => item.Tag === Tag); @@ -865,7 +869,7 @@ export const addBooster = async (ItemType: string, time: number, accountId: stri existingBooster.ExpiryDate = Math.max(existingBooster.ExpiryDate, currentTime) + time; inventory.markModified(`Boosters.${itemIndex}.ExpiryDate`); } else { - Boosters.push({ ItemType, ExpiryDate: currentTime + time }) - 1; + Boosters.push({ ItemType, ExpiryDate: currentTime + time }); } await inventory.save(); diff --git a/src/services/itemDataService.ts b/src/services/itemDataService.ts index f45f759b..df3e2b78 100644 --- a/src/services/itemDataService.ts +++ b/src/services/itemDataService.ts @@ -1,5 +1,4 @@ import { getIndexAfter } from "@/src/helpers/stringHelpers"; -import { logger } from "@/src/utils/logger"; import { dict_de, dict_en, @@ -54,7 +53,6 @@ export const getWeaponType = (weaponName: string): WeaponTypeInternal => { const weaponType = weaponInfo.productCategory; if (!weaponType) { - logger.error(`unknown weapon category for item ${weaponName}`); throw new Error(`unknown weapon category for item ${weaponName}`); } @@ -83,7 +81,6 @@ export const getItemCategoryByUniqueName = (uniqueName: string): string => { const index = getIndexAfter(uniqueName, splitWord); if (index === -1) { - logger.error(`error parsing item category ${uniqueName}`); throw new Error(`error parsing item category ${uniqueName}`); } const category = uniqueName.substring(index).split("/")[0]; diff --git a/src/services/loadoutService.ts b/src/services/loadoutService.ts index 37f91612..f9c385c5 100644 --- a/src/services/loadoutService.ts +++ b/src/services/loadoutService.ts @@ -1,12 +1,10 @@ import { Loadout } from "@/src/models/inventoryModels/loadoutModel"; -import { logger } from "@/src/utils/logger"; export const getLoadout = async (accountId: string) => { const loadout = await Loadout.findOne({ loadoutOwnerId: accountId }); if (!loadout) { - logger.error(`loadout not found for account ${accountId}`); - throw new Error("loadout not found"); + throw new Error(`loadout not found for account ${accountId}`); } return loadout; diff --git a/src/services/personalRoomsService.ts b/src/services/personalRoomsService.ts index c2d0b629..1392ce46 100644 --- a/src/services/personalRoomsService.ts +++ b/src/services/personalRoomsService.ts @@ -1,12 +1,10 @@ import { PersonalRooms } from "@/src/models/personalRoomsModel"; -import { logger } from "@/src/utils/logger"; export const getPersonalRooms = async (accountId: string) => { const personalRooms = await PersonalRooms.findOne({ personalRoomsOwnerId: accountId }); if (!personalRooms) { - logger.error(`personal rooms not found for account ${accountId}`); - throw new Error("personal rooms not found"); + throw new Error(`personal rooms not found for account ${accountId}`); } return personalRooms; }; diff --git a/src/services/purchaseService.ts b/src/services/purchaseService.ts index 8496934d..502f0c21 100644 --- a/src/services/purchaseService.ts +++ b/src/services/purchaseService.ts @@ -204,9 +204,12 @@ export const handleStoreItemAcquisition = async ( } } switch (storeCategory) { - default: - purchaseResponse = await addItem(accountId, internalName, quantity); + default: { + const inventory = await getInventory(accountId); + purchaseResponse = await addItem(inventory, internalName, quantity); + await inventory.save(); break; + } case "Types": purchaseResponse = await handleTypesPurchase(internalName, accountId, quantity); break; @@ -237,7 +240,8 @@ export const slotPurchaseNameToSlotName: SlotPurchase = { // // number of frames = extra - slots + 2 const handleSlotPurchase = async ( slotPurchaseNameFull: string, - accountId: string + accountId: string, + quantity: number ): Promise<{ InventoryChanges: IInventoryChanges }> => { logger.debug(`slot name ${slotPurchaseNameFull}`); const slotPurchaseName = parseSlotPurchaseName( @@ -246,19 +250,21 @@ const handleSlotPurchase = async ( logger.debug(`slot purchase name ${slotPurchaseName}`); const slotName = slotPurchaseNameToSlotName[slotPurchaseName].name; - const slotsPerPurchase = slotPurchaseNameToSlotName[slotPurchaseName].slotsPerPurchase; + const slotsPurchased = slotPurchaseNameToSlotName[slotPurchaseName].slotsPerPurchase * quantity; - await updateSlots(accountId, slotName, slotsPerPurchase, slotsPerPurchase); + const inventory = await getInventory(accountId); + updateSlots(inventory, slotName, slotsPurchased, slotsPurchased); + await inventory.save(); - logger.debug(`added ${slotsPerPurchase} slot ${slotName}`); + logger.debug(`added ${slotsPurchased} slot ${slotName}`); return { InventoryChanges: { [slotName]: { count: 0, platinum: 1, - Slots: slotsPerPurchase, - Extra: slotsPerPurchase + Slots: slotsPurchased, + Extra: slotsPurchased } } }; @@ -277,6 +283,7 @@ const handleBoosterPackPurchase = async ( BoosterPackItems: "", InventoryChanges: {} }; + const inventory = await getInventory(accountId); for (let i = 0; i != quantity; ++i) { for (const weights of pack.rarityWeightsPerRoll) { const result = getRandomWeightedReward(pack.components, weights); @@ -286,11 +293,12 @@ const handleBoosterPackPurchase = async ( result.type.split("/Lotus/").join("/Lotus/StoreItems/") + ',{"lvl":0};'; combineInventoryChanges( purchaseResponse.InventoryChanges, - (await addItem(accountId, result.type, result.itemCount)).InventoryChanges + (await addItem(inventory, result.type, result.itemCount)).InventoryChanges ); } } } + await inventory.save(); return purchaseResponse; }; @@ -303,12 +311,16 @@ const handleTypesPurchase = async ( const typeCategory = getStoreItemTypesCategory(typesName); logger.debug(`type category ${typeCategory}`); switch (typeCategory) { - default: - return await addItem(accountId, typesName, quantity); + default: { + const inventory = await getInventory(accountId); + const resp = await addItem(inventory, typesName, quantity); + await inventory.save(); + return resp; + } case "BoosterPacks": return await handleBoosterPackPurchase(typesName, accountId, quantity); case "SlotItems": - return await handleSlotPurchase(typesName, accountId); + return await handleSlotPurchase(typesName, accountId, quantity); } }; diff --git a/src/services/shipCustomizationsService.ts b/src/services/shipCustomizationsService.ts index ddf70f59..26aef04e 100644 --- a/src/services/shipCustomizationsService.ts +++ b/src/services/shipCustomizationsService.ts @@ -47,7 +47,6 @@ export const handleSetShipDecorations = async ( const roomToPlaceIn = rooms.find(room => room.Name === placedDecoration.Room); if (!roomToPlaceIn) { - logger.error("room not found"); throw new Error("room not found"); } @@ -59,7 +58,6 @@ export const handleSetShipDecorations = async ( ); if (existingDecorationIndex === -1) { - logger.error("decoration to be moved not found"); throw new Error("decoration to be moved not found"); } @@ -143,13 +141,11 @@ export const handleSetPlacedDecoInfo = async (accountId: string, req: ISetPlaced const room = personalRooms.Ship.Rooms.find(room => room.Name === req.Room); if (!room) { - logger.error("room not found"); throw new Error("room not found"); } const placedDeco = room.PlacedDecos?.find(x => x._id.toString() == req.DecoId); if (!placedDeco) { - logger.error("deco not found"); throw new Error("deco not found"); } diff --git a/src/services/shipService.ts b/src/services/shipService.ts index f654721d..0925a409 100644 --- a/src/services/shipService.ts +++ b/src/services/shipService.ts @@ -1,6 +1,5 @@ import { Ship } from "@/src/models/shipModel"; import { ILoadoutDatabase } from "@/src/types/saveLoadoutTypes"; -import { logger } from "@/src/utils/logger"; import { Types } from "mongoose"; export const createShip = async ( @@ -26,7 +25,6 @@ export const getShip = async (shipId: Types.ObjectId, fieldSelection: string = " const ship = await Ship.findOne({ _id: shipId }, fieldSelection); if (!ship) { - logger.error(`error finding a ship with id ${shipId.toString()}`); throw new Error(`error finding a ship with id ${shipId.toString()}`); } @@ -39,7 +37,6 @@ export const getShipLean = async (shipOwnerId: string) => { }>("LoadOutInventory.LoadOutPresets"); if (!ship) { - logger.error(`error finding a ship for account ${shipOwnerId}`); throw new Error(`error finding a ship for account ${shipOwnerId}`); } diff --git a/src/types/inventoryTypes/commonInventoryTypes.ts b/src/types/inventoryTypes/commonInventoryTypes.ts index f7026c0c..ccc5851e 100644 --- a/src/types/inventoryTypes/commonInventoryTypes.ts +++ b/src/types/inventoryTypes/commonInventoryTypes.ts @@ -78,8 +78,9 @@ export interface IEquipmentSelection { hide?: boolean; } -export interface IEquipmentClient extends Omit { +export interface IEquipmentClient extends Omit { ItemId: IOid; + UpgradesExpiry?: IMongoDate; } export enum EquipmentFeatures { @@ -112,6 +113,9 @@ export interface IEquipmentDatabase { UnlockLevel?: number; Expiry?: IMongoDate; SkillTree?: string; + OffensiveUpgrade?: string; + DefensiveUpgrade?: string; + UpgradesExpiry?: Date; ArchonCrystalUpgrades?: IArchonCrystalUpgrade[]; _id: Types.ObjectId; } diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index d608a232..1f43c918 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -10,8 +10,6 @@ import { IEquipmentDatabase } from "@/src/types/inventoryTypes/commonInventoryTypes"; -//Document extends will be deleted soon. TODO: delete and migrate uses to ... -export interface IInventoryDatabaseDocument extends IInventoryDatabase, Document {} export interface IInventoryDatabase extends Omit< IInventoryResponse, @@ -515,13 +513,15 @@ export interface IFusionTreasure { Sockets: number; } +export interface IHelminthFoodRecord { + ItemType: string; + Date: number; +} + export interface IHelminthResource { ItemType: string; Count: number; - RecentlyConvertedResources?: { - ItemType: string; - Date: number; - }[]; + RecentlyConvertedResources?: IHelminthFoodRecord[]; } export interface IInfestedFoundry { diff --git a/src/types/purchaseTypes.ts b/src/types/purchaseTypes.ts index f2b1ff9b..19e8ff33 100644 --- a/src/types/purchaseTypes.ts +++ b/src/types/purchaseTypes.ts @@ -1,3 +1,5 @@ +import { IInfestedFoundry } from "./inventoryTypes/inventoryTypes"; + export interface IPurchaseRequest { PurchaseParams: IPurchaseParams; buildLabel: string; @@ -25,8 +27,10 @@ export interface ICurrencyChanges { export type IInventoryChanges = { [_ in SlotNames]?: IBinChanges; -} & ICurrencyChanges & - Record; +} & ICurrencyChanges & { InfestedFoundry?: IInfestedFoundry } & Record< + string, + IBinChanges | number | object[] | IInfestedFoundry + >; export interface IPurchaseResponse { InventoryChanges: IInventoryChanges; diff --git a/static/fixed_responses/allScans.json b/static/fixed_responses/allScans.json index 8f186d29..938f7dd8 100644 --- a/static/fixed_responses/allScans.json +++ b/static/fixed_responses/allScans.json @@ -4346,5 +4346,17 @@ { "scans": 9999, "type": "/Lotus/Weapons/Infested/Melee/InfBoomerang/InfBoomerangSpawnAvatar" + }, + { + "scans": 9999, + "type": "/Lotus/Types/Game/CrewShip/GrineerDestroyer/DeepSpace/GrineerDSDestroyerAvatar" + }, + { + "scans": 9999, + "type": "/Lotus/Types/Game/CrewShip/GrineerDestroyer/Saturn/GrineerSaturnDestroyerAvatar" + }, + { + "scans": 9999, + "type": "/Lotus/Types/Game/CrewShip/GrineerDestroyer/GrineerDestroyerAvatar" } ] diff --git a/static/fixed_responses/getSkuCatalog.json b/static/fixed_responses/getSkuCatalog.json new file mode 100644 index 00000000..b6157ea0 --- /dev/null +++ b/static/fixed_responses/getSkuCatalog.json @@ -0,0 +1,3856 @@ +{ + "Prices": [ + { + "productId": 17, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 18, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 160, + "listPrice": 19.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 257, + "listPrice": 199.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 258, + "listPrice": 99.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 259, + "listPrice": 49.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 785, + "listPrice": 19.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 786, + "listPrice": 39.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 787, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 861, + "listPrice": 29.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 979, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2000, + "listPrice": 49.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2001, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2004, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2005, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2006, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2007, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2008, + "listPrice": 77.77, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2009, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2010, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2011, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2012, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2013, + "listPrice": 77.77, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2014, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2015, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2016, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2017, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2018, + "listPrice": 77.77, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2019, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2020, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2021, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2022, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2023, + "listPrice": 77.77, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2025, + "listPrice": 149.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2026, + "listPrice": 99.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2027, + "listPrice": 49.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2028, + "listPrice": 149.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2029, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2030, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2031, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2032, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2033, + "listPrice": 77.77, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2035, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2037, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2038, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2039, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2040, + "listPrice": 77.77, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2041, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2042, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2043, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2044, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2045, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2046, + "listPrice": 77.77, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2047, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2049, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2050, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2051, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2052, + "listPrice": 77.77, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2054, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2055, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2058, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2059, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2060, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2061, + "listPrice": 77.77, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2062, + "listPrice": 24.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2066, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2071, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2072, + "listPrice": 19.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2075, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2081, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2085, + "listPrice": 24.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2089, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2092, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2095, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2098, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2100, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2102, + "listPrice": 15.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 2105, + "listPrice": 19.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3000, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3001, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3002, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3003, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3004, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3005, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3006, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3007, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3008, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3009, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3010, + "listPrice": 149.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3011, + "listPrice": 99.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3012, + "listPrice": 49.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3013, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3014, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3015, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3016, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3017, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3018, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3019, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3020, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3021, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3022, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3023, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3024, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3025, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3026, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3027, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3028, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3029, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3033, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3038, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3041, + "listPrice": 24.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3044, + "listPrice": 19.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3047, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3050, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3053, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3054, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3057, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3060, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 3063, + "listPrice": 19.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4000, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4001, + "listPrice": 77.77, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4015, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4016, + "listPrice": 77.77, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4020, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4021, + "listPrice": 77.77, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4022, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4023, + "listPrice": 77.77, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4024, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4025, + "listPrice": 77.77, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4100, + "listPrice": 19.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4101, + "listPrice": 39.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4102, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4103, + "listPrice": 99.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4105, + "listPrice": 19.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4106, + "listPrice": 39.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4107, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4108, + "listPrice": 99.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4109, + "listPrice": 19.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4110, + "listPrice": 39.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4111, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4112, + "listPrice": 99.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4113, + "listPrice": 19.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4114, + "listPrice": 39.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4115, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4116, + "listPrice": 99.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4117, + "listPrice": 19.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4118, + "listPrice": 39.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4119, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4120, + "listPrice": 99.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4121, + "listPrice": 19.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4122, + "listPrice": 39.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4123, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 4124, + "listPrice": 99.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6000, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6002, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6003, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6004, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6005, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6006, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6007, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6008, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6009, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6010, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6011, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6012, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6013, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6014, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6015, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6016, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6017, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6018, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6019, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6020, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6021, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6022, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6024, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6025, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6026, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6027, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6028, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6029, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6030, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6031, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6032, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6033, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6034, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6035, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6036, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6038, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6039, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6040, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6041, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6042, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6043, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6044, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6045, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6046, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6047, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6048, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6049, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6050, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6051, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6052, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6053, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6054, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6055, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6056, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6057, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6058, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6059, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6060, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6061, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6062, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6063, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6064, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6065, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6066, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6067, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6068, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6069, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6070, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6071, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6072, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6073, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6074, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6075, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6076, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6077, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6078, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6079, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6080, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6081, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6082, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6083, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6084, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6085, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6086, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6087, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6088, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6089, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6090, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6091, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6092, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6093, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6094, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6095, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6096, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6097, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6098, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6099, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6100, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6101, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6102, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6103, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6104, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6105, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6106, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6107, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6108, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6109, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6110, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6111, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6112, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6113, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6114, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6115, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6116, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6117, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6118, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6119, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6120, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6121, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6122, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6123, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6124, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6125, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6126, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6127, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6128, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6129, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6130, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6131, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6132, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6133, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6134, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6135, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6136, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6137, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6138, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6139, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6140, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6141, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6142, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6143, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6144, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6145, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6146, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6147, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6148, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6149, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6150, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6151, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6152, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6153, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6154, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6155, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6156, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6157, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6158, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6159, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6160, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6161, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6162, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6163, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6164, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6165, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6166, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6167, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6168, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6169, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6170, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6171, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6172, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6173, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6174, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6175, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6176, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6177, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6178, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6179, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6180, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6181, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6182, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6183, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6184, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6185, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6186, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6187, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6188, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6195, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6190, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6191, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6192, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6193, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6194, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6196, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6197, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6198, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6199, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6200, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6201, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6202, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6203, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6204, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6205, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6206, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6207, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6208, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6209, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6210, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6211, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6212, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6213, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6214, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6215, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6216, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6217, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6218, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6219, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6220, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6221, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6222, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6223, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6224, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6225, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6226, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6227, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6228, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6229, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6230, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6231, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6232, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6233, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6234, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6235, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6236, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6237, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6238, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6239, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6240, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6241, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6242, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6250, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6251, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6252, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6253, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6254, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6255, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6256, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6257, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6258, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6259, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6260, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6261, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6262, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6263, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6264, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6265, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6266, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6267, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6268, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6269, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6270, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6271, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6272, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6273, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6274, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6275, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6276, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6277, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6278, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6279, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6280, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6281, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6282, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6283, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6284, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6285, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6286, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6287, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6288, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6289, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6290, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6291, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6292, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6293, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6294, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6295, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6296, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6297, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6298, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6299, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6300, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6301, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6302, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6303, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6304, + "listPrice": 2.49, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6305, + "listPrice": 2.49, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6306, + "listPrice": 2.49, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6307, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6308, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6309, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6310, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6311, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6312, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6313, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6314, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6315, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6316, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6317, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6318, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6319, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6320, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6321, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6322, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6323, + "listPrice": 2.49, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6324, + "listPrice": 2.49, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6325, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6326, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6327, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6328, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6329, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6330, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6331, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6332, + "listPrice": 2.49, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6333, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6334, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6335, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6336, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6337, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6338, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6339, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6340, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6341, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6342, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6343, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6344, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6345, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6346, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6347, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6348, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6349, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6350, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6351, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6352, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6353, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6354, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6355, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6356, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6357, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6358, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6359, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6360, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6361, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6362, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6363, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6364, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6365, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6366, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6367, + "listPrice": 2.49, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6368, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6369, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6370, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6371, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6372, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6373, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6374, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6375, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6376, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6377, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6378, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6379, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6380, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6381, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6382, + "listPrice": 2.49, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6383, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6384, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6385, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6386, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6387, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6388, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6389, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6390, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6391, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6392, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6393, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6394, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6395, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6396, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6397, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6398, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6399, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6400, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6401, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6402, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6403, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6404, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6405, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6406, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6407, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6408, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6409, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6410, + "listPrice": 2.49, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6411, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6412, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6413, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6414, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6415, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6416, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6417, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6418, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6419, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6420, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6421, + "listPrice": 2.49, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6422, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6423, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6424, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6425, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6426, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6427, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6428, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6429, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6430, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6431, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6432, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6433, + "listPrice": 2.49, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6434, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6435, + "listPrice": 2.49, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6436, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6437, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6438, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6439, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6440, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6441, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6442, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6443, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6444, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6445, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6446, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6447, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6448, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6449, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6450, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6451, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6452, + "listPrice": 2.49, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6453, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6454, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6455, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6456, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6457, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6458, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6459, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6460, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6461, + "listPrice": 5.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6462, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6463, + "listPrice": 2.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6464, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6465, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6466, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6467, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 6468, + "listPrice": 1.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 7000, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 7001, + "listPrice": 6.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 7002, + "listPrice": 14.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 7003, + "listPrice": 39.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 7004, + "listPrice": 59.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 7005, + "listPrice": 119.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 7008, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 9000, + "listPrice": 149.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 9001, + "listPrice": 99.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 9002, + "listPrice": 49.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 9003, + "listPrice": 19.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 9004, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 9005, + "listPrice": 4.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10000, + "listPrice": 19.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10003, + "listPrice": 24.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10019, + "listPrice": 29.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10020, + "listPrice": 9.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10024, + "listPrice": 49.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10025, + "listPrice": 79.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10026, + "listPrice": 139.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10027, + "listPrice": 49.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10028, + "listPrice": 49.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10029, + "listPrice": 30, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10030, + "listPrice": 60, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10031, + "listPrice": 90, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10032, + "listPrice": 90, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10033, + "listPrice": 40.01, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10034, + "listPrice": 10.01, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10035, + "listPrice": 19.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10036, + "listPrice": 39.99, + "currencyCode": "USD", + "owned": false + }, + { + "productId": 10037, + "listPrice": 54.99, + "currencyCode": "USD", + "owned": false + } + ] +} diff --git a/static/webui/index.html b/static/webui/index.html index af629d1f..e5c4eca8 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -278,7 +278,8 @@
Account
- +

+
diff --git a/static/webui/script.js b/static/webui/script.js index b3354132..139ca59a 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -956,6 +956,12 @@ function unlockFocusSchool(upgradeType) { }); } +function doHelminthUnlockAll() { + revalidateAuthz(() => { + $.post("/api/infestedFoundry.php?" + window.authz + "&mode=custom_unlockall"); + }); +} + // Powersuit Route single.getRoute("#powersuit-route").on("beforeload", function () {