diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..5e90659 --- /dev/null +++ b/TODO.md @@ -0,0 +1,14 @@ +# Shops TODO + + +### Server Shops +- [X] Add option to customize main gui +- [ ] Record transactions +- [ ] Fully implement filtering +- [X] Add the quick material select to new item gui +- [ ] Make command shop items be able to execute multiple commands +- [ ] In-game settings editor maybe + + +### Villager Trades +- [ ] TBD \ No newline at end of file diff --git a/src/main/java/ca/tweetzy/shops/api/cart/CartContent.java b/src/main/java/ca/tweetzy/shops/api/cart/CartContent.java index 6197aa0..3f92d4c 100644 --- a/src/main/java/ca/tweetzy/shops/api/cart/CartContent.java +++ b/src/main/java/ca/tweetzy/shops/api/cart/CartContent.java @@ -40,6 +40,10 @@ default double getSellSubtotal(final int actualQty) { return getItem().getSellPrice() * actualQty; } + default double getBuySubtotal(final int actualQty) { + return getItem().getBuyPrice() * actualQty; + } + default TransactionResult executeSell(@NonNull final Player player) { if (!(getItem() instanceof ItemShopContent itemShopContent)) { return TransactionResult.ERROR; diff --git a/src/main/java/ca/tweetzy/shops/api/shop/AbstractShopContent.java b/src/main/java/ca/tweetzy/shops/api/shop/AbstractShopContent.java index 57b6c09..974dd55 100644 --- a/src/main/java/ca/tweetzy/shops/api/shop/AbstractShopContent.java +++ b/src/main/java/ca/tweetzy/shops/api/shop/AbstractShopContent.java @@ -3,14 +3,12 @@ import ca.tweetzy.flight.comp.enums.CompMaterial; import ca.tweetzy.flight.settings.TranslationEntry; import ca.tweetzy.flight.settings.TranslationManager; -import ca.tweetzy.flight.utils.ItemUtil; import ca.tweetzy.flight.utils.QuickItem; import ca.tweetzy.shops.Shops; import ca.tweetzy.shops.api.SynchronizeResult; -import ca.tweetzy.shops.api.currency.AbstractCurrency; import ca.tweetzy.shops.impl.shop.CommandShopContent; import ca.tweetzy.shops.impl.shop.ItemShopContent; -import ca.tweetzy.shops.settings.Settings; +import ca.tweetzy.shops.model.NumberHelper; import ca.tweetzy.shops.settings.Translations; import lombok.AllArgsConstructor; import lombok.NonNull; @@ -125,6 +123,12 @@ public ItemStack generateDisplayItem(ShopContentDisplayType displayType, int pur genItem.name(commandShopContent.getName()); } + String formattedPriceBuy = isCurrencyOfItem() ? (int) this.buyPrice + " " + getCurrencyDisplayName() : NumberHelper.format(this.buyPrice); + String formattedPriceBuyTotal = isCurrencyOfItem() ? (int) this.buyPrice * purchaseQty + " " + getCurrencyDisplayName() : NumberHelper.format(this.buyPrice * purchaseQty); + + String formattedPriceSell = isCurrencyOfItem() ? (int) this.sellPrice + " " + getCurrencyDisplayName() : NumberHelper.format(this.sellPrice); + String formattedPriceSellTotal = isCurrencyOfItem() ? (int) this.sellPrice * purchaseQty + " " + getCurrencyDisplayName() : NumberHelper.format(this.sellPrice * purchaseQty); + if (displayType == ShopContentDisplayType.SHOP_EDIT) { genItem.lore(TranslationManager.list(Translations.GUI_SHOP_EDIT_ITEMS_ITEM_CONTENT_LORE, "is_buy_enabled", TranslationManager.string(this.allowBuy ? Translations.ENABLED : Translations.DISABLED), @@ -149,15 +153,15 @@ public ItemStack generateDisplayItem(ShopContentDisplayType displayType, int pur ); final List buyInfo = switch (displayType) { - case CART -> TranslationManager.list(Translations.GUI_CART_ITEMS_ITEM_CONTENT_BUY_INFO, "shop_item_buy_price", this.buyPrice); - case CHECKOUT -> TranslationManager.list(Translations.GUI_CHECKOUT_ITEMS_ITEM_CONTENT_BUY_INFO, "shop_item_buy_price", this.buyPrice); - default -> TranslationManager.list(Translations.GUI_SHOP_CONTENTS_ITEMS_ITEM_CONTENT_BUY_INFO, "shop_item_buy_price", this.buyPrice); + case CART -> TranslationManager.list(Translations.GUI_CART_ITEMS_ITEM_CONTENT_BUY_INFO, "shop_item_buy_price", formattedPriceBuy); + case CHECKOUT -> TranslationManager.list(Translations.GUI_CHECKOUT_ITEMS_ITEM_CONTENT_BUY_INFO, "shop_item_buy_price", formattedPriceBuy); + default -> TranslationManager.list(Translations.GUI_SHOP_CONTENTS_ITEMS_ITEM_CONTENT_BUY_INFO, "shop_item_buy_price", formattedPriceBuy); }; final List sellInfo = switch (displayType) { - case CART -> TranslationManager.list(Translations.GUI_CART_ITEMS_ITEM_CONTENT_SELL_INFO, "shop_item_sell_price", this.sellPrice); - case CHECKOUT -> TranslationManager.list(Translations.GUI_CHECKOUT_ITEMS_ITEM_CONTENT_SELL_INFO, "shop_item_sell_price", this.sellPrice); - default -> TranslationManager.list(Translations.GUI_SHOP_CONTENTS_ITEMS_ITEM_CONTENT_SELL_INFO, "shop_item_sell_price", this.sellPrice); + case CART -> TranslationManager.list(Translations.GUI_CART_ITEMS_ITEM_CONTENT_SELL_INFO, "shop_item_sell_price", formattedPriceSell); + case CHECKOUT -> TranslationManager.list(Translations.GUI_CHECKOUT_ITEMS_ITEM_CONTENT_SELL_INFO, "shop_item_sell_price", formattedPriceSell); + default -> TranslationManager.list(Translations.GUI_SHOP_CONTENTS_ITEMS_ITEM_CONTENT_SELL_INFO, "shop_item_sell_price",formattedPriceSell); }; final List minBuyInfo = switch (displayType) { @@ -167,14 +171,18 @@ public ItemStack generateDisplayItem(ShopContentDisplayType displayType, int pur }; final List buyInfoTotal = switch (displayType) { - case CART -> TranslationManager.list(Translations.GUI_CART_ITEMS_ITEM_CONTENT_BUY_INFO_TOTAL, "shop_item_buy_price_total", this.buyPrice * purchaseQty, "shop_item_purchase_qty", purchaseQty); - case CHECKOUT -> TranslationManager.list(Translations.GUI_CHECKOUT_ITEMS_ITEM_CONTENT_BUY_INFO_TOTAL, "shop_item_buy_price_total", this.buyPrice * purchaseQty, "shop_item_purchase_qty", purchaseQty); + case CART -> + TranslationManager.list(Translations.GUI_CART_ITEMS_ITEM_CONTENT_BUY_INFO_TOTAL, "shop_item_buy_price_total", formattedPriceBuyTotal, "shop_item_purchase_qty", purchaseQty); + case CHECKOUT -> + TranslationManager.list(Translations.GUI_CHECKOUT_ITEMS_ITEM_CONTENT_BUY_INFO_TOTAL, "shop_item_buy_price_total", formattedPriceBuyTotal, "shop_item_purchase_qty", purchaseQty); default -> TranslationManager.list(Translations.GUI_SHOP_CONTENTS_ITEMS_ITEM_CONTENT_MIN_BUY_INFO, "shop_item_purchase_qty", this.minPurchaseQty); }; final List sellInfoTotal = switch (displayType) { - case CART -> TranslationManager.list(Translations.GUI_CART_ITEMS_ITEM_CONTENT_SELL_INFO_TOTAL, "shop_item_sell_price_total", this.sellPrice * purchaseQty, "shop_item_purchase_qty", purchaseQty); - case CHECKOUT -> TranslationManager.list(Translations.GUI_CHECKOUT_ITEMS_ITEM_CONTENT_SELL_INFO_TOTAL, "shop_item_sell_price_total", this.sellPrice * purchaseQty, "shop_item_purchase_qty", purchaseQty); + case CART -> + TranslationManager.list(Translations.GUI_CART_ITEMS_ITEM_CONTENT_SELL_INFO_TOTAL, "shop_item_sell_price_total", formattedPriceSellTotal, "shop_item_purchase_qty", purchaseQty); + case CHECKOUT -> + TranslationManager.list(Translations.GUI_CHECKOUT_ITEMS_ITEM_CONTENT_SELL_INFO_TOTAL, "shop_item_sell_price_total", formattedPriceSellTotal, "shop_item_purchase_qty", purchaseQty); default -> TranslationManager.list(Translations.GUI_SHOP_CONTENTS_ITEMS_ITEM_CONTENT_MIN_BUY_INFO, "shop_item_purchase_qty", this.minPurchaseQty); }; diff --git a/src/main/java/ca/tweetzy/shops/gui/user/ShopCheckoutGUI.java b/src/main/java/ca/tweetzy/shops/gui/user/ShopCheckoutGUI.java index bb6aebd..f29da6d 100644 --- a/src/main/java/ca/tweetzy/shops/gui/user/ShopCheckoutGUI.java +++ b/src/main/java/ca/tweetzy/shops/gui/user/ShopCheckoutGUI.java @@ -10,6 +10,9 @@ import ca.tweetzy.shops.api.shop.ShopContentDisplayType; import ca.tweetzy.shops.gui.ShopsBaseGUI; import ca.tweetzy.shops.model.ItemParser; +import ca.tweetzy.shops.model.NumberHelper; +import ca.tweetzy.shops.model.Taxer; +import ca.tweetzy.shops.model.VariableHelper; import ca.tweetzy.shops.settings.Settings; import ca.tweetzy.shops.settings.Translations; import lombok.NonNull; @@ -99,12 +102,28 @@ private void drawSelectedItem() { } private void drawPriceBreakdown() { + final double subtotal = this.checkoutItem.getBuySubtotal(this.checkoutItem.getQuantity()); + final double total = Taxer.getTaxedTotal(subtotal); + + + final String numberFormatSub = this.checkoutItem.getItem().isCurrencyOfItem() ? (int) subtotal + " " + this.checkoutItem.getItem().getCurrencyDisplayName() : NumberHelper.format(subtotal); + final String numberFormatTotal = this.checkoutItem.getItem().isCurrencyOfItem() ? (int) total + " " + this.checkoutItem.getItem().getCurrencyDisplayName() : NumberHelper.format(total); + + List base = TranslationManager.list(this.player, Translations.GUI_CHECKOUT_ITEMS_BREAKDOWN_LORE, + "checkout_item_qty", this.checkoutItem.getQuantity(), + "checkout_item_buy_subtotal", numberFormatSub, + "checkout_item_buy_total", numberFormatTotal + ); + + VariableHelper.replaceVariable(base, "%checkout_tax_info%", Settings.TAX_ENABLED.getBoolean() ? + TranslationManager.string(player, Translations.GUI_CHECKOUT_ITEMS_BREAKDOWN_LORE_HAS_TAX, "tax_rate", Settings.TAX_AMOUNT.getDouble()) + : + TranslationManager.string(player, Translations.GUI_CHECKOUT_ITEMS_BREAKDOWN_LORE_NO_TAX), false); + + //checkout_tax_info setItem(getRows() - 3, 4, QuickItem .of(Settings.GUI_CHECKOUT_ITEMS_BREAKDOWN.getItemStack()) .name(TranslationManager.string(this.player, Translations.GUI_CHECKOUT_ITEMS_BREAKDOWN_NAME)) - .lore(TranslationManager.list(this.player, Translations.GUI_CHECKOUT_ITEMS_BREAKDOWN_LORE, - "checkout_item_qty", this.checkoutItem.getQuantity(), - "checkout_item_buy_subtotal", this.checkoutItem.getQuantity() * this.checkoutItem.getItem().getBuyPrice() - )).make()); + .lore(base).make()); } } diff --git a/src/main/java/ca/tweetzy/shops/model/NumberHelper.java b/src/main/java/ca/tweetzy/shops/model/NumberHelper.java new file mode 100644 index 0000000..9631b33 --- /dev/null +++ b/src/main/java/ca/tweetzy/shops/model/NumberHelper.java @@ -0,0 +1,15 @@ +package ca.tweetzy.shops.model; + +import ca.tweetzy.shops.settings.Settings; +import lombok.experimental.UtilityClass; + +import java.text.NumberFormat; +import java.util.Locale; + +@UtilityClass +public final class NumberHelper { + + public String format(final double total) { + return NumberFormat.getCurrencyInstance(new Locale.Builder().setLanguage(Settings.CURRENCY_FORMAT_LANGUAGE.getString()).setRegion(Settings.CURRENCY_FORMAT_COUNTRY.getString()).build()).format(total); + } +} diff --git a/src/main/java/ca/tweetzy/shops/settings/Settings.java b/src/main/java/ca/tweetzy/shops/settings/Settings.java index 22a5367..0b7a6d2 100644 --- a/src/main/java/ca/tweetzy/shops/settings/Settings.java +++ b/src/main/java/ca/tweetzy/shops/settings/Settings.java @@ -12,9 +12,11 @@ public final class Settings extends FlightSettings { public static ConfigEntry PREFIX = create("prefix", "&8[&eShops&8]").withComment("The prefix for the plugin"); public static ConfigEntry LANGUAGE = create("language", "en_us").withComment("The primary language of the plugin"); public static ConfigEntry CURRENCY_DEFAULT_SELECTED = create("settings.currency.default selection", "Vault/Vault").withComment("The default currency selection, PluginName/CurrencyName -> Ex. Vault/Vault"); - public static ConfigEntry CURRENCY_VAULT_SYMBOL = create("settings.currency.vault symbol", "$").withComment("When using default/vault currency, what symbol should be used."); + public static ConfigEntry CURRENCY_VAULT_SYMBOL = create("settings.currency.vault symbol", "$").withComment("When using default/vault currency, what symbol should be used. Mainly for admin guis"); public static ConfigEntry CURRENCY_USE_ITEM_ONLY = create("settings.currency.use item only", false).withComment("If true, Shops will only allow the usage of another item for currency."); public static ConfigEntry CURRENCY_BLACKLISTED = create("settings.currency.black listed", List.of("UltraEconomy:Gems")).withComment("A list of owning plugins & the currency to be blacklisted. Ex. UltraEconomy:Gems"); + public static ConfigEntry CURRENCY_FORMAT_LANGUAGE = create("settings.currency.format.language", "en").withComment("An ISO 639 alpha-2 or alpha-3 language code."); + public static ConfigEntry CURRENCY_FORMAT_COUNTRY = create("settings.currency.format.country", "US").withComment("An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code."); public static ConfigEntry TAX_ENABLED = create("settings.tax.enabled", false).withComment("If true, will apply sales tax to the total when a user is buying an item"); public static ConfigEntry TAX_AMOUNT = create("settings.tax.percentage", 13.0).withComment("The tax percentage. By default it's 13%"); public static ConfigEntry TAX_SELL = create("settings.tax.tax on sell", false).withComment("If true, selling items to a shop will remove tax percentage"); diff --git a/src/main/java/ca/tweetzy/shops/settings/Translations.java b/src/main/java/ca/tweetzy/shops/settings/Translations.java index 272604d..123af31 100644 --- a/src/main/java/ca/tweetzy/shops/settings/Translations.java +++ b/src/main/java/ca/tweetzy/shops/settings/Translations.java @@ -136,19 +136,19 @@ public Translations(@NonNull JavaPlugin plugin) { ); public static final TranslationEntry GUI_CART_ITEMS_ITEM_CONTENT_BUY_INFO = create("gui.cart.items.content.lore.buy lore", - "&7Buy Price (&fx&e1&7)&f: &a$%shop_item_buy_price%" + "&7Buy Price (&fx&e1&7)&f: &a%shop_item_buy_price%" ); public static final TranslationEntry GUI_CART_ITEMS_ITEM_CONTENT_SELL_INFO = create("gui.cart.items.content.lore.sell lore", - "&7Sell Price (&fx&e1&7)&f: &a$%shop_item_sell_price%" + "&7Sell Price (&fx&e1&7)&f: &a%shop_item_sell_price%" ); public static final TranslationEntry GUI_CART_ITEMS_ITEM_CONTENT_BUY_INFO_TOTAL = create("gui.cart.items.content.lore.buy total lore", - "&7Buy &fx&e%shop_item_purchase_qty%&f: &a$%shop_item_buy_price_total%" + "&7Buy &fx&e%shop_item_purchase_qty%&f: &a%shop_item_buy_price_total%" ); public static final TranslationEntry GUI_CART_ITEMS_ITEM_CONTENT_SELL_INFO_TOTAL = create("gui.cart.items.content.lore.sell total lore", - "&7Sell &fx&e%shop_item_purchase_qty%&f: &a$%shop_item_sell_price_total%" + "&7Sell &fx&e%shop_item_purchase_qty%&f: &a%shop_item_sell_price_total%" ); public static final TranslationEntry GUI_CART_ITEMS_ITEM_CONTENT_SELECTED_QTY_INFO = create("gui.cart.items.content.lore.selected qty lore", @@ -179,16 +179,21 @@ public Translations(@NonNull JavaPlugin plugin) { "&8&m------------------------------", "&7Selected Quantity&F: &e%checkout_item_qty%", "", - "&7&e&lTaxes & Discounts", - "&7", "&A&LPurchase", - "&7Subtotal&F: &a$%checkout_item_buy_subtotal%", - "&7", - "&c&lSell", + "&7Subtotal&F: &a%checkout_item_buy_subtotal%", + "", + "&7&e&lTaxes", + "%checkout_tax_info%", + "", + "&A&LPurchase (Total)", + "&7Total&F: &a%checkout_item_buy_total%", "", "&8&m------------------------------" ); + public static final TranslationEntry GUI_CHECKOUT_ITEMS_BREAKDOWN_LORE_HAS_TAX = create("gui.checkout.items.breakdown.has tax lore", "&eServer Tax Rate &F(&7%tax_rate%&a%&f)"); + public static final TranslationEntry GUI_CHECKOUT_ITEMS_BREAKDOWN_LORE_NO_TAX = create("gui.checkout.items.breakdown.no tax lore", "&cNo tax is currently applied."); + public static final TranslationEntry GUI_CHECKOUT_ITEMS_ITEM_CONTENT_BASE_LORE = create("gui.checkout.items.content.lore.base lore", "&8&m------------------------------", @@ -202,19 +207,19 @@ public Translations(@NonNull JavaPlugin plugin) { ); public static final TranslationEntry GUI_CHECKOUT_ITEMS_ITEM_CONTENT_BUY_INFO = create("gui.checkout.items.content.lore.buy lore", - "&7Buy Price (&fx&e1&7)&f: &a$%shop_item_buy_price%" + "&7Buy Price (&fx&e1&7)&f: &a%shop_item_buy_price%" ); public static final TranslationEntry GUI_CHECKOUT_ITEMS_ITEM_CONTENT_SELL_INFO = create("gui.checkout.items.content.lore.sell lore", - "&7Sell Price (&fx&e1&7)&f: &a$%shop_item_sell_price%" + "&7Sell Price (&fx&e1&7)&f: &a%shop_item_sell_price%" ); public static final TranslationEntry GUI_CHECKOUT_ITEMS_ITEM_CONTENT_BUY_INFO_TOTAL = create("gui.checkout.items.content.lore.buy total lore", - "&7Buy &fx&e%shop_item_purchase_qty%&f: &a$%shop_item_buy_price_total%" + "&7Buy &fx&e%shop_item_purchase_qty%&f: &a%shop_item_buy_price_total%" ); public static final TranslationEntry GUI_CHECKOUT_ITEMS_ITEM_CONTENT_SELL_INFO_TOTAL = create("gui.checkout.items.content.lore.sell total lore", - "&7Sell &fx&e%shop_item_purchase_qty%&f: &a$%shop_item_sell_price_total%" + "&7Sell &fx&e%shop_item_purchase_qty%&f: &a%shop_item_sell_price_total%" ); public static final TranslationEntry GUI_CHECKOUT_ITEMS_ITEM_CONTENT_SELECTED_QTY_INFO = create("gui.checkout.items.content.lore.selected qty lore", @@ -308,11 +313,11 @@ public Translations(@NonNull JavaPlugin plugin) { ); public static final TranslationEntry GUI_SHOP_CONTENTS_ITEMS_ITEM_CONTENT_BUY_INFO = create("gui.shop contents.items.content.lore.buy lore", - "&7Buy Price (&fx&e1&7)&f: &a$%shop_item_buy_price%" + "&7Buy Price (&fx&e1&7)&f: &a%shop_item_buy_price%" ); public static final TranslationEntry GUI_SHOP_CONTENTS_ITEMS_ITEM_CONTENT_SELL_INFO = create("gui.shop contents.items.content.lore.sell lore", - "&7Sell Price (&fx&e1&7)&f: &a$%shop_item_sell_price%" + "&7Sell Price (&fx&e1&7)&f: &a%shop_item_sell_price%" ); public static final TranslationEntry GUI_SHOP_CONTENTS_ITEMS_ITEM_CONTENT_MIN_BUY_INFO = create("gui.shop contents.items.content.lore.min buy lore",