diff --git a/app/Classes/General/Open1688/SignatureUtil.php b/app/Classes/General/Open1688/SignatureUtil.php
new file mode 100644
index 00000000..91c21005
--- /dev/null
+++ b/app/Classes/General/Open1688/SignatureUtil.php
@@ -0,0 +1,31 @@
+ $v ) {
+ $paramToSign = $k . $v;
+ Array_push ( $paramsToSign, $paramToSign );
+ }
+ sort ( $paramsToSign );
+ $implodeParams = implode ( $paramsToSign );
+ $pathAndParams = $path . $implodeParams;
+ $sign = hash_hmac ( "sha1", $pathAndParams, config('open1688.app_secret'), true );
+ $signHexWithLowcase = bin2hex ( $sign );
+ $signHexUppercase = strtoupper ( $signHexWithLowcase );
+ return $signHexUppercase;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/app/Classes/General/Open1688Helper.php b/app/Classes/General/Open1688Helper.php
new file mode 100644
index 00000000..70bbf8eb
--- /dev/null
+++ b/app/Classes/General/Open1688Helper.php
@@ -0,0 +1,79 @@
+ "{\"keyword\":\"$keyword\",\"beginPage\":$page,\"pageSize\":18,\"country\":\"en\"}",
+ ];
+
+ return self::getFromOpen1688($requestData, config('open1688.product_search_keyword_api'));
+ }
+
+ public static function productDetail($offerId) {
+ $requestData = [
+ 'offerDetailParam' => "{\"offerId\":$offerId,\"country\":\"en\"}",
+ ];
+
+ return self::getFromOpen1688($requestData, config('open1688.product_detail_api'));
+ }
+
+ private static function getFromOpen1688($requestData, $apiName) {
+ $requestData["access_token"] = config('open1688.access_token');
+
+ $signaturedStr = self::generateRequestSignature($apiName, $requestData);
+ $url = config('open1688.url') . $apiName . "/" . config('open1688.app_key') . "?_aop_signature=" . $signaturedStr;
+
+
+ foreach($requestData as $k => $v) {
+ $url = $url . "&$k=$v";
+ }
+
+ try {
+ $client = new \GuzzleHttp\Client(['verify' => false]);
+ $response = $client->request('GET', $url);
+ $body = $response->getBody();
+ $contents = json_decode($body, true);
+
+ return $contents['result']['result'];
+ } catch(\GuzzleHttp\Exception\RequestException $exception){
+ throw new MalformedRequestException(json_decode($exception->getResponse()->getBody()->getContents(), true)['error_message']);
+ }
+
+ }
+
+ private static function generateRequestSignature ($apiName, $requestData) {
+ $pathToSign = self::generateAPIPath($apiName);
+ $signaturedStr = SignatureUtil::signature ($pathToSign, $requestData);
+
+ return $signaturedStr;
+ }
+
+ private static function generateAPIPath($apiName) {
+ $urlResult = "";
+ $defs = array (
+ $urlResult,
+ "param2",
+ "/",
+ "1",
+ "/",
+ "com.alibaba.fenxiao.crossborder",
+ "/",
+ $apiName,
+ "/",
+ config('open1688.app_key')
+ );
+
+ $urlResult = implode ( $defs );
+
+ return $urlResult;
+ }
+
+}
diff --git a/app/Classes/Modules/Open1688/ControllersLogic/GetProductDetailLogic.php b/app/Classes/Modules/Open1688/ControllersLogic/GetProductDetailLogic.php
new file mode 100644
index 00000000..1ec60540
--- /dev/null
+++ b/app/Classes/Modules/Open1688/ControllersLogic/GetProductDetailLogic.php
@@ -0,0 +1,84 @@
+ 'Get product detail',
+ 'message' => 'You have successfully get 1688 product detail'
+ ];
+ }
+
+ /**
+ * @param Request $request
+ * @return JsonResponse
+ * @throws ErrorException
+ */
+ public function logic(Request $request) : JsonResponse
+ {
+ $result = Open1688Helper::productDetail($request->route('offer_id'));
+ $productAttribute = [];
+ $variants = [];
+ $uniqueVariants = [];
+ $variantInfo = [];
+ $priceList = [];
+ $variantKeyCombinationOrder = [];
+
+ foreach ($result['productAttribute'] as $attr) {
+ $productAttribute[$attr['attributeName']] = array_key_exists($attr['attributeName'], $productAttribute) ? $productAttribute[$attr['attributeName']] . ", " . $attr['value'] : $attr['value'];
+ }
+
+ $result['productAttribute'] = $productAttribute;
+
+ foreach ($result['productSkuInfos'] as $sku) {
+ $uniqueVariantKey = '';
+ foreach ($sku['skuAttributes'] as $skuAttr) {
+ if (count($variantKeyCombinationOrder) < count($sku['skuAttributes'])) {
+ array_push($variantKeyCombinationOrder, $skuAttr['attributeName']);
+ }
+ if (!in_array($skuAttr['value'], $uniqueVariants)) {
+ $variants[$skuAttr['attributeName']][] = [
+ 'image' => isset($skuAttr['skuImageUrl']) ? $skuAttr['skuImageUrl'] : null,
+ 'value' => $skuAttr['value']
+ ];
+ }
+
+ array_push($uniqueVariants, $skuAttr['value']);
+
+ $uniqueVariantKey .= $skuAttr['value'];
+ }
+
+ $price = isset($sku['price']) ? $sku['price'] : $sku['consignPrice'];
+
+ $variantInfo[$uniqueVariantKey] = [
+ 'skuId' => $sku['skuId'],
+ 'amountOnSale' => $sku['amountOnSale'],
+ 'price' => $price,
+ ];
+ array_push($priceList, $price);
+ }
+
+ $result['variants'] = $variants;
+ $result['variantInfo'] = $variantInfo;
+
+ $minPrice = min($priceList);
+ $maxPrice = max($priceList);
+
+ $result['priceRange'] = $minPrice === $maxPrice ? $minPrice : "CNY ¥$minPrice - CNY ¥$maxPrice";
+ $result['variantKeyCombinationOrder'] = $variantKeyCombinationOrder;
+
+ return $this->response(['data' => $result]);
+ }
+}
diff --git a/app/Classes/Modules/Open1688/ControllersLogic/KeywordSearchProductLogic.php b/app/Classes/Modules/Open1688/ControllersLogic/KeywordSearchProductLogic.php
new file mode 100644
index 00000000..526c3b1f
--- /dev/null
+++ b/app/Classes/Modules/Open1688/ControllersLogic/KeywordSearchProductLogic.php
@@ -0,0 +1,36 @@
+ 'Search 1688 Products',
+ 'message' => 'You have successfully retrieved a list of products from 1688'
+ ];
+ }
+
+ /**
+ * @param Request $request
+ * @return JsonResponse
+ * @throws ErrorException
+ */
+ public function logic(Request $request) : JsonResponse
+ {
+ $result = Open1688Helper::productSearchKeyword($request->input('keyword'), $request->input('page'));
+
+ return $this->response($result);
+ }
+}
diff --git a/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php
index 9bab107f..68072a6e 100644
--- a/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php
+++ b/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php
@@ -72,14 +72,32 @@ class CreatePurchaseOrderTransactionLogic extends AbstractControllerLogic
$billNumber = $this->generatesTransactionBillNumber->execute('PO-');
- $total = collect($request->input('products'))->sum(function($product){
+ $products = $request->input('products');
+
+ if ($request->input('pushToExisting')) {
+ $transaction = $booking->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first();
+
+ if ($transaction) {
+ foreach ($transaction->transactionDetails as $detail) {
+ array_push($products, [
+ 'stockCode' => $detail->product_code,
+ 'description' => $detail->product_name,
+ 'quantity' => $detail->quantity,
+ 'unit_price' => $detail->price,
+ 'total' => $detail->amount
+ ]);
+ }
+ }
+ }
+
+ $total = collect($products)->sum(function($product){
return $product['quantity'] * floatval(str_replace(',', '', $product['unit_price']));
});
$object = new TransactionObject($billNumber, TransactionType::PURCHASE_ORDER, $booking->company->id, 1,
1, PaymentMethodType::CASH,
$total, $total, $booking->fix_currency_id, $booking->fix_currency_id,
- 1, 0, 0, null, ApprovalStatus::PENDING_SUBMISSION, $request->input('products'));
+ 1, 0, 0, null, ApprovalStatus::PENDING_SUBMISSION, $products);
$transaction = $this->createPurchaseOrderTransactionProcessor->execute($booking, $object);
diff --git a/app/Http/Controllers/Open1688/Open1688Controller.php b/app/Http/Controllers/Open1688/Open1688Controller.php
new file mode 100644
index 00000000..2ed20540
--- /dev/null
+++ b/app/Http/Controllers/Open1688/Open1688Controller.php
@@ -0,0 +1,30 @@
+execute($request);
+ }
+
+ /**
+ * @param Request $request
+ * @param GetProductDetailLogic $logic
+ * @return JsonResponse
+ */
+ public function getProductDetail(Request $request, GetProductDetailLogic $logic): JsonResponse {
+ return $logic->execute($request);
+ }
+
+}
diff --git a/app/Http/Resources/TransactionDetailResource.php b/app/Http/Resources/TransactionDetailResource.php
index 4257a9fb..63c6661b 100644
--- a/app/Http/Resources/TransactionDetailResource.php
+++ b/app/Http/Resources/TransactionDetailResource.php
@@ -14,14 +14,23 @@ class TransactionDetailResource extends JsonResource
*/
public function toArray($request)
{
-
+ $item_from_1688 = str_contains($this->product_code, 'offerId');
+ $offer_id_1688 = null;
+ if ($item_from_1688) {
+ $offerId = explode(',', $this->product_code)[0];
+ $offer_id_1688 = substr($offerId, strpos($offerId, ':') + 1);
+ }
+
+
return [
'id' => $this->id,
'stockCode' => $this->product_code,
'description' => $this->product_name,
'quantity' => $this->quantity,
'unit_price' => (double) $this->price,
- 'total' => (double) $this->amount
+ 'total' => (double) $this->amount,
+ 'item_from_1688' => $item_from_1688,
+ 'offer_id_1688' => $offer_id_1688
];
}
}
diff --git a/config/open1688.php b/config/open1688.php
new file mode 100644
index 00000000..7cf948f4
--- /dev/null
+++ b/config/open1688.php
@@ -0,0 +1,11 @@
+ env('OPEN_1688_APP_KEY', ''),
+ 'app_secret' => env('OPEN_1688_APP_SECRET', ''),
+ 'access_token' => env('open_1688_ACCESS_TOKEN', ''),
+ 'refresh_token' => env('open_1688_REFRESH_TOKEN', ''),
+ 'url' => env('OPEN_1688_URL', ''),
+ 'product_search_keyword_api' => env('OPEN_1688_PRODUCT_SEARCH_KEYWORD', ''),
+ 'product_detail_api' => env('OPEN_1688_PRODUCT_DETAIL', ''),
+];
diff --git a/resources/assets/vue/components/bookings/elements/AlibabaProductOverviewComponent.vue b/resources/assets/vue/components/bookings/elements/AlibabaProductOverviewComponent.vue
new file mode 100644
index 00000000..7c5f43fa
--- /dev/null
+++ b/resources/assets/vue/components/bookings/elements/AlibabaProductOverviewComponent.vue
@@ -0,0 +1,34 @@
+
+
+
+
+
+

Nothing To Show Here
+