feat: integrate dynamic geofence fetching, service area spatial boundaries, partner store profiles & editing with Leaflet maps, custom store portal icons, QR distribution charts with geographic/LGU filters, and optimize admin dashboards
This commit is contained in:
@@ -8,6 +8,8 @@ use App\Models\Household;
|
||||
use App\Models\PartnerStore;
|
||||
use App\Models\QrCode;
|
||||
use App\Models\StoreInventoryAdjustment;
|
||||
use App\Models\StoreSale;
|
||||
use App\Models\User;
|
||||
use App\Services\Store\StoreOperations;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -146,9 +148,10 @@ class AdminPartnerStoreController extends ApiController
|
||||
|
||||
try {
|
||||
$household = Household::findOrFail($data['household_id']);
|
||||
$sale = $this->ops->sellToHousehold(
|
||||
$sale = $this->ops->sell(
|
||||
$store,
|
||||
$household,
|
||||
null,
|
||||
(int) $data['quantity'],
|
||||
$retailPrice,
|
||||
);
|
||||
@@ -370,4 +373,173 @@ class AdminPartnerStoreController extends ApiController
|
||||
'total_sold_codes' => (int) $store->sales()->sum('quantity'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function distributionChart(Request $request, PartnerStore $store): JsonResponse
|
||||
{
|
||||
$period = $request->input('period', 'daily');
|
||||
|
||||
$driver = \DB::getDriverName();
|
||||
$isSqlite = $driver === 'sqlite';
|
||||
|
||||
$query = $store->sales();
|
||||
|
||||
switch ($period) {
|
||||
case 'weekly':
|
||||
$dateExpression = $isSqlite
|
||||
? "strftime('%Y-W%W', COALESCE(sold_at, created_at))"
|
||||
: "DATE_FORMAT(COALESCE(sold_at, created_at), '%x-W%v')";
|
||||
|
||||
$rows = $query
|
||||
->selectRaw("{$dateExpression} as label, SUM(quantity) as total")
|
||||
->whereRaw("COALESCE(sold_at, created_at) >= ?", [now()->subWeeks(12)->startOfWeek()])
|
||||
->groupByRaw($dateExpression)
|
||||
->orderByRaw($dateExpression)
|
||||
->get();
|
||||
break;
|
||||
|
||||
case 'monthly':
|
||||
$dateExpression = $isSqlite
|
||||
? "strftime('%Y-%m', COALESCE(sold_at, created_at))"
|
||||
: "DATE_FORMAT(COALESCE(sold_at, created_at), '%Y-%m')";
|
||||
|
||||
$rows = $query
|
||||
->selectRaw("{$dateExpression} as label, SUM(quantity) as total")
|
||||
->whereRaw("COALESCE(sold_at, created_at) >= ?", [now()->subMonths(12)->startOfMonth()])
|
||||
->groupByRaw($dateExpression)
|
||||
->orderByRaw($dateExpression)
|
||||
->get();
|
||||
break;
|
||||
|
||||
case 'overall':
|
||||
$dateExpression = $isSqlite
|
||||
? "strftime('%Y-%m', COALESCE(sold_at, created_at))"
|
||||
: "DATE_FORMAT(COALESCE(sold_at, created_at), '%Y-%m')";
|
||||
|
||||
$rows = $query
|
||||
->selectRaw("{$dateExpression} as label, SUM(quantity) as total")
|
||||
->groupByRaw($dateExpression)
|
||||
->orderByRaw($dateExpression)
|
||||
->get();
|
||||
break;
|
||||
|
||||
default: // daily — last 30 days
|
||||
$dateExpression = $isSqlite
|
||||
? "date(COALESCE(sold_at, created_at))"
|
||||
: "DATE(COALESCE(sold_at, created_at))";
|
||||
|
||||
$rows = $query
|
||||
->selectRaw("{$dateExpression} as label, SUM(quantity) as total")
|
||||
->whereRaw("COALESCE(sold_at, created_at) >= ?", [now()->subDays(29)->startOfDay()])
|
||||
->groupByRaw($dateExpression)
|
||||
->orderByRaw($dateExpression)
|
||||
->get();
|
||||
break;
|
||||
}
|
||||
|
||||
return $this->ok([
|
||||
'period' => $period,
|
||||
'labels' => $rows->pluck('label'),
|
||||
'values' => $rows->pluck('total')->map(fn ($v) => (int) $v),
|
||||
'total_distributed' => (int) $store->sales()->sum('quantity'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function overallDistributionChart(Request $request): JsonResponse
|
||||
{
|
||||
$period = $request->input('period', 'daily');
|
||||
|
||||
$user = $request->user();
|
||||
$isSuperAdmin = $user && $user->role === User::ROLE_SUPER_ADMIN;
|
||||
|
||||
$storeQuery = PartnerStore::query();
|
||||
|
||||
if ($isSuperAdmin) {
|
||||
if ($request->filled('tenant_id')) {
|
||||
$storeQuery->withoutGlobalScopes()->where('tenant_id', $request->integer('tenant_id'));
|
||||
} else {
|
||||
$storeQuery->withoutGlobalScopes();
|
||||
}
|
||||
} else {
|
||||
if ($user && $user->tenant_id) {
|
||||
$storeQuery->where('tenant_id', $user->tenant_id);
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->filled('service_area_id')) {
|
||||
$storeQuery->whereHas('barangay.serviceAreas', function ($q) use ($request) {
|
||||
$q->where('service_areas.id', $request->integer('service_area_id'));
|
||||
});
|
||||
}
|
||||
|
||||
if ($request->filled('barangay_id')) {
|
||||
$storeQuery->where('barangay_id', $request->integer('barangay_id'));
|
||||
}
|
||||
|
||||
$storeIds = $storeQuery->pluck('id');
|
||||
|
||||
$driver = \DB::getDriverName();
|
||||
$isSqlite = $driver === 'sqlite';
|
||||
|
||||
$query = StoreSale::query()->whereIn('store_id', $storeIds);
|
||||
|
||||
switch ($period) {
|
||||
case 'weekly':
|
||||
$dateExpression = $isSqlite
|
||||
? "strftime('%Y-W%W', COALESCE(sold_at, created_at))"
|
||||
: "DATE_FORMAT(COALESCE(sold_at, created_at), '%x-W%v')";
|
||||
|
||||
$rows = $query
|
||||
->selectRaw("{$dateExpression} as label, SUM(quantity) as total")
|
||||
->whereRaw("COALESCE(sold_at, created_at) >= ?", [now()->subWeeks(12)->startOfWeek()])
|
||||
->groupByRaw($dateExpression)
|
||||
->orderByRaw($dateExpression)
|
||||
->get();
|
||||
break;
|
||||
|
||||
case 'monthly':
|
||||
$dateExpression = $isSqlite
|
||||
? "strftime('%Y-%m', COALESCE(sold_at, created_at))"
|
||||
: "DATE_FORMAT(COALESCE(sold_at, created_at), '%Y-%m')";
|
||||
|
||||
$rows = $query
|
||||
->selectRaw("{$dateExpression} as label, SUM(quantity) as total")
|
||||
->whereRaw("COALESCE(sold_at, created_at) >= ?", [now()->subMonths(12)->startOfMonth()])
|
||||
->groupByRaw($dateExpression)
|
||||
->orderByRaw($dateExpression)
|
||||
->get();
|
||||
break;
|
||||
|
||||
case 'overall':
|
||||
$dateExpression = $isSqlite
|
||||
? "strftime('%Y-%m', COALESCE(sold_at, created_at))"
|
||||
: "DATE_FORMAT(COALESCE(sold_at, created_at), '%Y-%m')";
|
||||
|
||||
$rows = $query
|
||||
->selectRaw("{$dateExpression} as label, SUM(quantity) as total")
|
||||
->groupByRaw($dateExpression)
|
||||
->orderByRaw($dateExpression)
|
||||
->get();
|
||||
break;
|
||||
|
||||
default: // daily — last 30 days
|
||||
$dateExpression = $isSqlite
|
||||
? "date(COALESCE(sold_at, created_at))"
|
||||
: "DATE(COALESCE(sold_at, created_at))";
|
||||
|
||||
$rows = $query
|
||||
->selectRaw("{$dateExpression} as label, SUM(quantity) as total")
|
||||
->whereRaw("COALESCE(sold_at, created_at) >= ?", [now()->subDays(29)->startOfDay()])
|
||||
->groupByRaw($dateExpression)
|
||||
->orderByRaw($dateExpression)
|
||||
->get();
|
||||
break;
|
||||
}
|
||||
|
||||
return $this->ok([
|
||||
'period' => $period,
|
||||
'labels' => $rows->pluck('label'),
|
||||
'values' => $rows->pluck('total')->map(fn ($v) => (int) $v),
|
||||
'total_distributed' => (int) $query->sum('quantity'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user