terminalmarket 0.13.3 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/tm.js +131 -19
- package/package.json +1 -1
package/bin/tm.js
CHANGED
|
@@ -713,34 +713,146 @@ program
|
|
|
713
713
|
// -----------------
|
|
714
714
|
program
|
|
715
715
|
.command("checkout")
|
|
716
|
-
.description("
|
|
717
|
-
.
|
|
716
|
+
.description("Create order from cart")
|
|
717
|
+
.option("--pickup", "Pick up at store")
|
|
718
|
+
.option("--delivery", "Delivery to address")
|
|
719
|
+
.option("--shipping", "Shipping (post/courier)")
|
|
720
|
+
.option("--phone <phone>", "Contact phone number")
|
|
721
|
+
.option("--address <address>", "Delivery/shipping address")
|
|
722
|
+
.option("-y, --yes", "Skip confirmation prompt")
|
|
723
|
+
.action(async (opts) => {
|
|
718
724
|
try {
|
|
719
725
|
const cartData = await apiGet("/cart");
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
726
|
+
const items = cartData.items || [];
|
|
727
|
+
|
|
728
|
+
if (items.length === 0) {
|
|
729
|
+
console.log(chalk.yellow("Your cart is empty. Add items first with: tm add <product-id>"));
|
|
723
730
|
return;
|
|
724
731
|
}
|
|
725
|
-
|
|
726
|
-
console.log(chalk.bold("Checkout"));
|
|
727
|
-
console.log("");
|
|
728
|
-
console.log("Your items:");
|
|
729
|
-
|
|
732
|
+
|
|
730
733
|
let total = 0;
|
|
731
|
-
|
|
734
|
+
console.log();
|
|
735
|
+
console.log(chalk.bold(" ═══ Checkout ═══"));
|
|
736
|
+
console.log();
|
|
737
|
+
items.forEach((item, i) => {
|
|
732
738
|
const name = item.name || item.product?.name || `Product #${item.productId}`;
|
|
733
739
|
const price = parseFloat(item.price ?? item.product?.price ?? 0);
|
|
734
|
-
const
|
|
740
|
+
const qty = item.quantity || 1;
|
|
741
|
+
const subtotal = price * qty;
|
|
735
742
|
total += subtotal;
|
|
736
|
-
console.log(` ${i + 1}. ${name} x${
|
|
743
|
+
console.log(` ${i + 1}. ${name} x${qty} = $${subtotal.toFixed(2)}`);
|
|
737
744
|
});
|
|
738
|
-
|
|
739
|
-
console.log(
|
|
740
|
-
console.log(
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
745
|
+
console.log();
|
|
746
|
+
console.log(chalk.bold(` Total: $${total.toFixed(2)}`));
|
|
747
|
+
console.log();
|
|
748
|
+
|
|
749
|
+
const hasDigitalOnly = items.length > 0 && items.every(it => {
|
|
750
|
+
const k = it.product?.productKind || it.productKind;
|
|
751
|
+
return k === "digital" || k === "saas";
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
let deliveryMethod = null;
|
|
755
|
+
if (opts.pickup) deliveryMethod = "pickup";
|
|
756
|
+
else if (opts.delivery) deliveryMethod = "delivery";
|
|
757
|
+
else if (opts.shipping) deliveryMethod = "shipping";
|
|
758
|
+
|
|
759
|
+
let phone = opts.phone || null;
|
|
760
|
+
let address = opts.address || null;
|
|
761
|
+
|
|
762
|
+
if (!hasDigitalOnly) {
|
|
763
|
+
// Try to pull phone/address from profile if not provided
|
|
764
|
+
if (!phone || !address) {
|
|
765
|
+
try {
|
|
766
|
+
const profile = await apiGet("/profile");
|
|
767
|
+
if (!phone && profile.phone) phone = profile.phone;
|
|
768
|
+
if (!address) {
|
|
769
|
+
const parts = [profile.address, profile.city, profile.country].filter(Boolean);
|
|
770
|
+
if (parts.length > 0) address = parts.join(", ");
|
|
771
|
+
}
|
|
772
|
+
} catch { /* ignore */ }
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
const inquirer = await import("inquirer").then(m => m.default);
|
|
776
|
+
|
|
777
|
+
// Ask delivery method interactively if not set
|
|
778
|
+
if (!deliveryMethod) {
|
|
779
|
+
const { method } = await inquirer.prompt([{
|
|
780
|
+
type: "list",
|
|
781
|
+
name: "method",
|
|
782
|
+
message: "Delivery method:",
|
|
783
|
+
choices: [
|
|
784
|
+
{ name: "🏪 Pick up at store", value: "pickup" },
|
|
785
|
+
{ name: "🚗 Delivery to address", value: "delivery" },
|
|
786
|
+
{ name: "📦 Shipping (post/courier)", value: "shipping" },
|
|
787
|
+
],
|
|
788
|
+
}]);
|
|
789
|
+
deliveryMethod = method;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// Ask phone if missing
|
|
793
|
+
if (!phone) {
|
|
794
|
+
const { inputPhone } = await inquirer.prompt([{
|
|
795
|
+
type: "input",
|
|
796
|
+
name: "inputPhone",
|
|
797
|
+
message: "Contact phone:",
|
|
798
|
+
validate: v => v.trim().length > 0 || "Phone is required",
|
|
799
|
+
}]);
|
|
800
|
+
phone = inputPhone.trim();
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Ask address if delivery/shipping and missing
|
|
804
|
+
if ((deliveryMethod === "delivery" || deliveryMethod === "shipping") && !address) {
|
|
805
|
+
const { inputAddress } = await inquirer.prompt([{
|
|
806
|
+
type: "input",
|
|
807
|
+
name: "inputAddress",
|
|
808
|
+
message: "Delivery address:",
|
|
809
|
+
validate: v => v.trim().length > 0 || "Address is required for delivery/shipping",
|
|
810
|
+
}]);
|
|
811
|
+
address = inputAddress.trim();
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// Confirmation
|
|
816
|
+
if (!opts.yes) {
|
|
817
|
+
const inquirer = await import("inquirer").then(m => m.default);
|
|
818
|
+
console.log();
|
|
819
|
+
if (deliveryMethod) console.log(chalk.dim(` Method: ${deliveryMethod}`));
|
|
820
|
+
if (phone) console.log(chalk.dim(` Phone: ${phone}`));
|
|
821
|
+
if (address) console.log(chalk.dim(` Address: ${address}`));
|
|
822
|
+
console.log();
|
|
823
|
+
const { confirm } = await inquirer.prompt([{
|
|
824
|
+
type: "confirm",
|
|
825
|
+
name: "confirm",
|
|
826
|
+
message: `Place order for $${total.toFixed(2)}?`,
|
|
827
|
+
default: true,
|
|
828
|
+
}]);
|
|
829
|
+
if (!confirm) {
|
|
830
|
+
console.log(chalk.yellow("Order cancelled."));
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// Create order via API
|
|
836
|
+
const orderPayload = {};
|
|
837
|
+
if (deliveryMethod) orderPayload.deliveryMethod = deliveryMethod;
|
|
838
|
+
if (phone) orderPayload.phone = phone;
|
|
839
|
+
if (address) orderPayload.shippingAddress = address;
|
|
840
|
+
|
|
841
|
+
const result = await apiPost("/orders", orderPayload);
|
|
842
|
+
|
|
843
|
+
console.log();
|
|
844
|
+
console.log(chalk.green.bold(" ✓ Order created!"));
|
|
845
|
+
const orderId = result.order?.id || result.id;
|
|
846
|
+
const orderNum = result.order?.orderNumber || result.orderNumber;
|
|
847
|
+
if (orderNum) console.log(` Order: ${chalk.bold(orderNum)}`);
|
|
848
|
+
else if (orderId) console.log(` Order ID: ${chalk.bold(orderId)}`);
|
|
849
|
+
console.log(` Total: $${total.toFixed(2)}`);
|
|
850
|
+
if (deliveryMethod) console.log(` Delivery: ${deliveryMethod}`);
|
|
851
|
+
if (phone) console.log(` Phone: ${phone}`);
|
|
852
|
+
if (address) console.log(` Address: ${address}`);
|
|
853
|
+
console.log();
|
|
854
|
+
console.log(chalk.dim(" View your orders: tm orders"));
|
|
855
|
+
console.log();
|
|
744
856
|
} catch (e) {
|
|
745
857
|
console.error(chalk.red(e?.message || String(e)));
|
|
746
858
|
process.exitCode = 1;
|