Merge branch 'feature-product' into development
WMS API/ECOMMERCE/pipeline/head There was a failure building this commit Details

This commit is contained in:
Bayu Lukman Yusuf 2026-02-26 08:47:45 +07:00
commit 95d0b6cdd6
7 changed files with 123 additions and 55 deletions

View File

@ -32,6 +32,7 @@ class AddressController extends Controller
'postal_code' => $address->postal_code,
'latitude' => $address->latitude,
'longitude' => $address->longitude,
'phone' => $address->phone,
];
});

View File

@ -10,6 +10,8 @@ use App\Repositories\Member\Transaction\TransactionRepository;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
class CheckoutController extends Controller
{
public function index(Request $request, MemberCartRepository $memberCartRepository)
@ -20,7 +22,7 @@ class CheckoutController extends Controller
$subtotal = $memberCartRepository->getSubtotal($request->input('location_id'));
$address_list = Address::where('user_id', $request->user()->id)->orderBy('is_primary','desc')->get();
$address_list = Address::where('user_id', auth()->user()->id)->orderBy('is_primary','desc')->get();
$total = $subtotal;
@ -92,19 +94,32 @@ class CheckoutController extends Controller
$request->merge(['location_id' => $location_id]);
$carts = $memberCartRepository->getList($request);
$shipping_list = collect($shippingRepository->getList([
"location_id" => $location_id,
"address_id" => $address_id,
"items" => $carts,
])['pricing'])->map(function($row){
return [
'courier' => $row['courier_code'],
'service' => $row['courier_service_code'],
'title' => $row['courier_name']." - ".$row['courier_service_name'],
'description' => $row['duration'],
'cost' => $row['shipping_fee'],
];
});
try{
$shipping_list = collect($shippingRepository->getList([
"location_id" => $location_id,
"address_id" => $address_id,
"items" => $carts,
])['pricing'] ?? [])->map(function($row){
return [
'courier' => $row['courier_code'],
'service' => $row['courier_service_code'],
'title' => $row['courier_name']." - ".$row['courier_service_name'],
'description' => $row['duration'],
'cost' => $row['shipping_fee'],
];
});
if (count($shipping_list) == 0) {
throw ValidationException::withMessages([
"message" => "Tidak dapat menghitung ongkir"
]);
}
}catch(\Exception $e){
throw ValidationException::withMessages([
"message" => $e->getMessage()
]);
}
return view('checkout.v1-delivery-1-shipping', [
'carts' => $request->user()->carts,
@ -117,7 +132,7 @@ class CheckoutController extends Controller
]);
} catch (\Exception $e) {
Log::info($e);
return redirect()->route('checkout.delivery')->with('error', 'Invalid checkout data');
return redirect()->route('checkout.delivery')->with('error', $e->getMessage() ?? 'Invalid checkout data');
}
}

View File

@ -96,13 +96,21 @@ class ShippingRepository
});
if ($hasLatLong){
$list = $biteship->rateByLatLong([
"origin_latitude" => $location->latitude,
"origin_longitude" => $location->longitude,
"destination_latitude" => $address->latitude,
"destination_longitude" => $address->longitude,
"items" => $items
]);
try{
$list = $biteship->rateByLatLong([
"origin_latitude" => $location->latitude,
"origin_longitude" => $location->longitude,
"destination_latitude" => $address->latitude,
"destination_longitude" => $address->longitude,
"items" => $items
]);
}catch(ValidationException $e){
$list = $biteship->rateByPostal([
"origin_postal_code" => $location->postal_code,
"destination_postal_code" => $address->postal_code,
"items" => $items
]);
}
}else{
$list = $biteship->rateByPostal([

View File

@ -5,6 +5,7 @@ namespace App\ThirdParty\Biteship;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
use Illuminate\Validation\ValidationException;
class Rate
{
@ -28,19 +29,29 @@ class Rate
$items) {
$url = env("BITESHIP_URL");
$key = env("BITESHIP_KEY");
$res = Http::withHeaders([
"authorization" => $key
])
->withBody(json_encode([
$body = [
"origin_latitude" => $origin_latitude,
"origin_longitude" => $origin_longitude,
"destination_latitude" => $destination_latitude,
"destination_longitude" => $destination_longitude,
"couriers" => env("BITESHIP_COURIER_ALL","grab,gojek,tiki,jnt,anteraja"),
"couriers" => env("BITESHIP_COURIER","grab,gojek,tiki,jnt,anteraja"),
"items" => $items
]), 'application/json')
];
$res = Http::withHeaders([
"authorization" => $key
])
->withBody(json_encode($body), 'application/json')
->post($url."/v1/rates/couriers");
if ($res->status() != 200 && $res->json()['error'] != null) {
Log::info(json_encode($res->json()));
Log::info($body);
throw ValidationException::withMessages([
"message" => $res->json()['error']
]);
}
if ($res->status() == 200)
return $res->json();
@ -73,6 +84,12 @@ class Rate
]), 'application/json')
->post($url."/v1/rates/couriers");
if ($res->status() != 200 && $res->json()['error'] != null) {
throw ValidationException::withMessages([
"message" => $res->json()['error']
]);
}
if ($res->status() == 200)
return $res->json();

View File

@ -83,7 +83,7 @@
<td class="py-3 ps-0">
<div class="d-flex align-items-center">
<a class="flex-shrink-0"
href="{{ route('product.detail', $cart->itemVariant->item->slug) }}">
href="{{ $cart->itemVariant->item->slug != null ? route('product.detail', $cart->itemVariant->item->slug) : '#' }}">
<img src="{{ $cart->itemReference->item->image_url ?? '' }}"
width="80" alt="{{ $cart->name ?? 'Product' }}">
</a>
@ -92,7 +92,7 @@
<div class="w-100 min-w-0 ps-2 ps-xl-3">
<h5 class="d-flex animate-underline mb-2">
<a class="d-block fs-sm fw-medium text-truncate animate-target"
href="{{ $cart->itemVariant->item->slug != null ? route('product.detail', [$cart->item->slug]) : '#' }}">{{ $cart->itemVariant->display_name ?? ($cart->itemVariant->description ?? 'Product Name') }}</a>
href="{{ $cart->itemVariant->item->slug != null ? route('product.detail', [$cart->itemVariant->item->slug]) : '#' }}">{{ $cart->itemVariant->display_name ?? ($cart->itemVariant->description ?? 'Product Name') }}</a>
</h5>
{{-- <ul class="list-unstyled gap-1 fs-xs mb-0">
<li><span class="text-body-secondary">Color:</span> <span

View File

@ -85,7 +85,7 @@
<aside class="col-lg-4 offset-xl-1" style="margin-top: -100px">
<div class="position-sticky top-0" style="padding-top: 100px">
<x-checkout.order-summary :subtotal="$subtotal" :total="$total" :savings="0" :tax="0"
:showEdit="true" :editUrl="route('second', ['checkout', 'v1-cart'])" />
:showEdit="true" :editUrl="route('cart.index')" />
</div>
</aside>
</div>

View File

@ -9,7 +9,7 @@
<div class="row pt-1 pt-sm-3 pt-lg-4 pb-2 pb-md-3 pb-lg-4 pb-xl-5">
{{-- show error message --}}
@if(session('error'))
@if (session('error'))
<div class="alert alert-danger">
{{ session('error') }}
</div>
@ -84,13 +84,14 @@
data-state="{{ $address->province->name }}"
data-postcode="{{ $address->postal_code }}"
data-phone="{{ $address->phone }}"
data-latitude="{{ $address->latitude }}"
data-longitude="{{ $address->longitude }}"
{{ $address->is_primary || $key === 0 ? 'selected' : '' }}>
{{ $address->label }} - {{ $address->name }},
{{ $address->address }}, {{ $address->city_name }},
{{ $address->province_name }} {{ $address->postal_code }}
{{ $address->address }}
@if ($address->is_primary)
<span
class="badge bg-primary ms-2">{{ __('checkout.primary') }}</span>
class="badge bg-primary ms-2">({{ __('checkout.primary') }})</span>
@endif
</option>
@endforeach
@ -100,7 +101,12 @@
<!-- Shipping Address (shown automatically) -->
<div id="shippingAddress" class="shipping-address mt-4" style="display: block;">
<h6 class="mb-3">{{ __('checkout.shipping_address') }}</h6>
<div class="d-flex justify-content-between">
<h6 class="mb-3">{{ __('checkout.shipping_address') }}</h6>
<a type="button" href="{{ route('addresses') }}"
class="btn btn-outline-primary btn-sm">Edit</a>
</div>
<div class="row g-3">
<div class="col-md-6">
<label for="firstName"
@ -108,11 +114,17 @@
<input type="text" class="form-control" id="firstName" readonly
style="border: none; background-color: #f8f9fa;">
</div>
<div class="col-md-6">
{{-- <div class="col-md-6">
<label for="lastName"
class="form-label">{{ __('checkout.last_name') }}</label>
<input type="text" class="form-control" id="lastName" readonly
style="border: none; background-color: #f8f9fa;">
</div> --}}
<div class="col-12">
<label for="phone"
class="form-label">{{ __('checkout.phone') }}</label>
<input type="tel" class="form-control" id="phone" readonly
style="border: none; background-color: #f8f9fa;">
</div>
<div class="col-12">
<label for="address"
@ -138,12 +150,19 @@
<input type="text" class="form-control" id="zip" readonly
style="border: none; background-color: #f8f9fa;">
</div>
<div class="col-12">
<label for="phone"
class="form-label">{{ __('checkout.phone') }}</label>
<input type="tel" class="form-control" id="phone" readonly
<div class="col-md-6">
<label for="latitude"
class="form-label">Latitude</label>
<input type="text" class="form-control" id="latitude" readonly
style="border: none; background-color: #f8f9fa;">
</div>
<div class="col-md-6">
<label for="longitude"
class="form-label">Longitude</label>
<input type="text" class="form-control" id="longitude" readonly
style="border: none; background-color: #f8f9fa;">
</div>
</div>
</div>
</div>
@ -170,8 +189,10 @@
<div class="mt-4">
<form action="{{ route('checkout.delivery.process') }}" method="post">
@csrf
<input type="hidden" name="delivery_method" id="deliveryMethodInput" value="shipping">
<input type="hidden" name="address_id" id="addressIdInput" value="{{ $address_list->first()->id }}">
<input type="hidden" name="delivery_method" id="deliveryMethodInput"
value="shipping">
<input type="hidden" name="address_id" id="addressIdInput"
value="{{ $address_list->first()->id }}">
<button type="submit" class="btn btn-lg btn-primary w-100"
id="continueButton">
<span
@ -203,14 +224,14 @@
<aside class="col-lg-4 offset-xl-1" style="margin-top: -100px">
<div class="position-sticky top-0" style="padding-top: 100px">
<x-checkout.order-summary :subtotal="$subtotal" :total="$total" :savings="0" :tax="0"
:showEdit="true" :editUrl="route('second', ['checkout', 'v1-cart'])" />
:showEdit="true" :editUrl="route('cart.index')" />
</div>
</aside>
</div>
</div>
</main>
@include('layouts.partials/footer')
@include('layouts.partials/footer2')
@endsection
@section('scripts')
@ -231,7 +252,8 @@
pickupOptions.style.display = 'none';
resetPickupSelection();
// Update button text for delivery
document.getElementById('continueButtonText').textContent = '{{ __("checkout.continue_to_shipping") }}';
document.getElementById('continueButtonText').textContent =
'{{ __('checkout.continue_to_shipping') }}';
// Update hidden input values
document.getElementById('deliveryMethodInput').value = 'delivery';
// Update address ID from selected address
@ -309,13 +331,14 @@
if (selectedOption && selectedOption.value) {
// Populate all shipping address form fields
document.getElementById('firstName').value = selectedOption.dataset.firstName || '';
document.getElementById('lastName').value = selectedOption.dataset.lastName || '';
// document.getElementById('lastName').value = selectedOption.dataset.lastName || '';
document.getElementById('address').value = selectedOption.dataset.address || '';
document.getElementById('city').value = selectedOption.dataset.city || '';
document.getElementById('state').value = selectedOption.dataset.state || '';
document.getElementById('zip').value = selectedOption.dataset.postcode || '';
document.getElementById('phone').value = selectedOption.dataset.phone || '';
document.getElementById('postcode').value = selectedOption.dataset.postcode || '';
document.getElementById('latitude').value = selectedOption.dataset.latitude || '';
document.getElementById('longitude').value = selectedOption.dataset.longitude || '';
// Update order summary with postcode
if (selectedOption.dataset.postcode) {
@ -337,25 +360,29 @@
if (this.value === 'new' || this.value === '') {
// Clear form fields for new address
document.getElementById('firstName').value = '';
document.getElementById('lastName').value = '';
// document.getElementById('lastName').value = '';
document.getElementById('address').value = '';
document.getElementById('city').value = '';
document.getElementById('state').value = '';
document.getElementById('zip').value = '';
document.getElementById('phone').value = '';
document.getElementById('postcode').value = '';
document.getElementById('latitude').value = '';
document.getElementById('longitude').value = '';
document.getElementById('zip').value = '';
// Clear address ID input
document.getElementById('addressIdInput').value = '';
} else {
// Populate form fields with selected address
document.getElementById('firstName').value = selectedOption.dataset.firstName || '';
document.getElementById('lastName').value = selectedOption.dataset.lastName || '';
// document.getElementById('lastName').value = selectedOption.dataset.lastName || '';
document.getElementById('address').value = selectedOption.dataset.address || '';
document.getElementById('city').value = selectedOption.dataset.city || '';
document.getElementById('state').value = selectedOption.dataset.state || '';
document.getElementById('zip').value = selectedOption.dataset.postcode || '';
document.getElementById('phone').value = selectedOption.dataset.phone || '';
document.getElementById('postcode').value = selectedOption.dataset.postcode || '';
document.getElementById('latitude').value = selectedOption.dataset.latitude || '';
document.getElementById('longitude').value = selectedOption.dataset.longitude || '';
document.getElementById('zip').value = selectedOption.dataset.postcode || '';
// Update address ID input
document.getElementById('addressIdInput').value = this.value;
@ -368,7 +395,7 @@
}
// Auto-update order summary when postcode changes
document.getElementById('postcode').addEventListener('input', function() {
document.getElementById('zip').addEventListener('input', function() {
if (this.value) {
updateOrderSummaryWithShipping();
}
@ -427,7 +454,7 @@
function updateOrderSummaryWithShipping() {
// Simulate shipping cost calculation based on postcode
const shippingCost = calculateShippingCost(document.getElementById('postcode').value);
const shippingCost = calculateShippingCost(document.getElementById('zip').value);
// Update order summary
const subtotalElement = document.getElementById('cart-subtotal');
@ -510,7 +537,7 @@
}
function validateDeliveryForm() {
const postcode = document.getElementById('postcode').value;
const postcode = document.getElementById('zip').value;
const firstName = document.getElementById('firstName').value;
const address = document.getElementById('address').value;
const city = document.getElementById('city').value;