585 lines
24 KiB
PHP
585 lines
24 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Admin\Api;
|
|
|
|
use App\Classes\Constant;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Admin;
|
|
use App\Models\Appointment;
|
|
use App\Models\Cart;
|
|
use App\Models\Item;
|
|
use App\Models\ItemHistory;
|
|
use App\Models\LabkitOrderItem;
|
|
use App\Models\LicenseNumberModel;
|
|
use App\Models\Patient;
|
|
use App\Models\PatientNote;
|
|
use App\Models\PatientPrescription;
|
|
use App\Models\ProfileQuestion;
|
|
use App\Models\Setting;
|
|
use App\Models\Telemedpro;
|
|
use DateInterval;
|
|
use DatePeriod;
|
|
use DateTime;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Routing\UrlGenerator;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use PhpParser\Node\Stmt\Const_;
|
|
use Illuminate\Auth\Access\AuthorizationException;
|
|
|
|
class ReportsController extends Controller
|
|
{
|
|
protected $url;
|
|
protected $user;
|
|
public function __construct(UrlGenerator $url)
|
|
{
|
|
$this->url = $url;
|
|
$this->user = Auth::guard('admin')->user();
|
|
}
|
|
public function providerReportFilters()
|
|
{
|
|
$providers = Telemedpro::select(
|
|
DB::raw("CONCAT(license_numbers.license_number,',',license_numbers.state) as provider_license_number"),
|
|
'appointments.patient_name',
|
|
'appointments.appointment_date',
|
|
'appointments.appointment_time',
|
|
'appointments.timezone',
|
|
'start_time',
|
|
'end_time',
|
|
'duration',
|
|
DB::raw("CONCAT(patients.first_name,',',patients.last_name) as patient_name"),
|
|
'patients.phone_no',
|
|
'patients.email',
|
|
'patients.address',
|
|
'patients.city',
|
|
'patients.state',
|
|
'patients.zip_code',
|
|
'patients.country',
|
|
'patients.gender',
|
|
'patients.dob',
|
|
'patients.height',
|
|
'patients.weight'
|
|
)
|
|
->LeftJoin('license_numbers', 'provider_id', 'telemed_pros.id')
|
|
->LeftJoin('appointments', 'appointments.telemed_pros_id', 'telemed_pros.id')
|
|
->leftJoin('patients', 'appointments.patient_id', 'patients.id')
|
|
->whereNotNull('appointments.start_time')
|
|
->whereNotNull('appointments.end_time')
|
|
->get();
|
|
|
|
foreach ($providers as $provider) {
|
|
$start_datetime = new DateTime($provider->start_time);
|
|
$diff = $start_datetime->diff(new DateTime($provider->end_time));
|
|
$duration = $diff->h . " hours " . $diff->i . " Min";
|
|
// dd($providers->duration,$duration);
|
|
$provider->duration = $duration;
|
|
}
|
|
|
|
return response()->json([
|
|
'provider_list' => $providers,
|
|
]);
|
|
}
|
|
public function providerReportPost(Request $request)
|
|
{
|
|
return response()->json([
|
|
'provider_list' => ''
|
|
]);
|
|
}
|
|
public function overviewReport(Request $request)
|
|
{
|
|
try {
|
|
$this->authorizeForUser($this->user, 'overview_analytics', new ProfileQuestion);
|
|
$start_date = $request->get('start_date');
|
|
$end_date = $request->get('end_date');
|
|
$totalOrdersStats = Cart::select(
|
|
DB::raw("sum(case when carts.status = 'completed' then 1 else 0 end) as total_sales"),
|
|
DB::raw("sum(case when carts.status = 'completed' then carts.total_amount else 0 end) as sales_amount"),
|
|
DB::raw("count(items.id) as products_sold")
|
|
)
|
|
->Join('items', 'items.cart_id', 'carts.id')
|
|
->where('carts.created_at', '>=', $start_date . " 00:00:00")
|
|
->where('carts.created_at', '<=', $end_date . " 23:59:59")
|
|
->where('carts.status', '=', 'completed')
|
|
->get();
|
|
$orderCollection = Cart::select(
|
|
'carts.id as order_id',
|
|
'carts.status',
|
|
'carts.email',
|
|
'carts.total_amount',
|
|
'carts.created_at as date',
|
|
DB::raw("CONCAT(carts.first_name,' ',carts.last_name) as patient_name")
|
|
)
|
|
->where('carts.created_at', '>=', $start_date . " 00:00:00")
|
|
->where('carts.created_at', '<=', $end_date . " 23:59:59")
|
|
->where('carts.status', '=', 'completed')
|
|
->get();
|
|
$orderData = $orderCollection->map(function ($query, $key) {
|
|
$patientType = $query->where('email', $query->email)->count();
|
|
$itemSold = Item::select(DB::raw("GROUP_CONCAT(title SEPARATOR ', ') as items"))
|
|
->where('cart_id', $query->order_id)
|
|
->leftJoin('plans_v1', 'items.plans_id', 'plans_v1.id');
|
|
$itemCount = $itemSold->count();
|
|
$products = $itemSold->first();
|
|
if ($patientType > 1)
|
|
$query->customer_type = 'returning';
|
|
else
|
|
$query->customer_type = 'new';
|
|
|
|
$query->products = $products->items ?? null;
|
|
$query->item_sold = $itemCount ?? 0;
|
|
|
|
$query->attribution = 'direct';
|
|
|
|
return $query;
|
|
});
|
|
$dates = [];
|
|
$sales = [];
|
|
$startDate = Carbon::parse($start_date);
|
|
$endDate = Carbon::parse($end_date);
|
|
for ($date = $startDate; $date->lte($endDate); $date->addDay()) {
|
|
$values = Cart::select(
|
|
DB::raw('DATE(created_at) as date'),
|
|
DB::raw("SUM(case when carts.status = 'completed' then carts.total_amount else 0 end) as amount")
|
|
)
|
|
->where('carts.created_at', '>=', $date->format("Y-m-d") . " 00:00:00")
|
|
->where('carts.created_at', '<=', $date->format("Y-m-d") . " 23:59:59")
|
|
->groupBy(DB::raw('DATE(created_at)'));
|
|
$graphsValues = $values->first();
|
|
|
|
$dates[] = $date->format("M d/y");
|
|
if ($graphsValues)
|
|
$sales[] = $graphsValues->amount;
|
|
else
|
|
$sales[] = 0;
|
|
}
|
|
$newUser = 0;
|
|
$returnUser = 0;
|
|
$newUsers = [];
|
|
$returningUsers = [];
|
|
//getting here unique rows for patient stats
|
|
$uniqueKeys = array_map(function ($item) {
|
|
return $item['email'];
|
|
}, $orderCollection->toArray());
|
|
|
|
$uniqueRecords = array_intersect_key($orderCollection->toArray(), array_unique($uniqueKeys));
|
|
$uniqueRecords = array_values($uniqueRecords);
|
|
|
|
foreach ($orderCollection as $userStats) {
|
|
$userStatus = Cart::where('email', $userStats->email)->count();
|
|
if ($userStatus > 1) {
|
|
$returnUser++;
|
|
$returningUsers[] = $userStats;
|
|
} else {
|
|
$newUser++;
|
|
$newUsers[] = $userStats;
|
|
}
|
|
};
|
|
|
|
$percentageReturning = 0;
|
|
$percentageNewuser = 0;
|
|
if ($returnUser > 0 || $newUser > 0) {
|
|
$percentageReturning = ($returnUser / ($returnUser + $newUser)) * 100;
|
|
$percentageNewuser = ($newUser / ($returnUser + $newUser)) * 100;
|
|
}
|
|
|
|
//check here users engagement
|
|
|
|
$newUserEngagement = $this->calculateEngagement($newUsers);
|
|
$returningUserEngagement = $this->calculateEngagement($returningUsers);
|
|
return response()->json([
|
|
'totals' => $totalOrdersStats,
|
|
'orders' => $orderData,
|
|
'chart' => [
|
|
'chart_dates' => $dates,
|
|
'chart_data' => $sales
|
|
],
|
|
'patient_stats' =>
|
|
[
|
|
'returning_users' => [$returnUser, round($percentageReturning, 0) . "%"],
|
|
'new_users' => [$newUser, round($percentageNewuser, 0) . "%"]
|
|
]
|
|
]);
|
|
} catch (AuthorizationException $e) {
|
|
return $e->getMessage();
|
|
}
|
|
}
|
|
public function ordersFilters()
|
|
{
|
|
$patient = Patient::select('id', DB::raw("CONCAT(first_name,' ',last_name) as patient_name"))->get();
|
|
return response()->json([
|
|
'patients' => $patient
|
|
|
|
]);
|
|
}
|
|
public function initialPatients()
|
|
{
|
|
$patients = Patient::select('id', DB::raw("CONCAT(first_name,' ',last_name) as patient_name"))
|
|
->limit(100)
|
|
->orderBy('patient_name', 'asc')
|
|
->get();
|
|
|
|
return response()->json([
|
|
'patients' => $patients
|
|
]);
|
|
}
|
|
|
|
public function searchPatients(Request $request)
|
|
{
|
|
$searchTerm = $request->input('term');
|
|
|
|
$patients = Patient::select('id', DB::raw("CONCAT(first_name,' ',last_name) as patient_name"))
|
|
->where(DB::raw("CONCAT(first_name,' ',last_name)"), 'LIKE', "%{$searchTerm}%")
|
|
->limit(500)
|
|
->orderBy('patient_name', 'asc')
|
|
->get();
|
|
|
|
return response()->json([
|
|
'patients' => $patients
|
|
]);
|
|
}
|
|
|
|
// Function to calculate engagement metrics
|
|
function calculateEngagement($users)
|
|
{
|
|
$totalUsers = count($users);
|
|
$completedOrders = 0;
|
|
$totalAmount = 0;
|
|
|
|
foreach ($users as $user) {
|
|
if ($user['status'] === 'delivered') {
|
|
$completedOrders++;
|
|
}
|
|
$totalAmount += floatval($user['total_amount']);
|
|
}
|
|
|
|
$orderCompletionRate = $totalUsers > 0 ? ($completedOrders / $totalUsers) * 100 : 0;
|
|
$averageOrderValue = $totalUsers > 0 ? $totalAmount / $totalUsers : 0;
|
|
|
|
return [
|
|
'total_users' => $totalUsers,
|
|
'completed_orders' => $completedOrders,
|
|
'order_completion_rate' => $orderCompletionRate,
|
|
'average_order_value' => $averageOrderValue
|
|
];
|
|
}
|
|
public function ordersReport(Request $request)
|
|
{
|
|
try {
|
|
$this->authorizeForUser($this->user, 'orders_analytics', new ProfileQuestion);
|
|
$start_date = $request->get('start_date');
|
|
$end_date = $request->get('end_date');
|
|
$status = $request->get('status');
|
|
$patient = $request->get('patient');
|
|
$query = Cart::select(
|
|
'carts.id as order_id',
|
|
'carts.status',
|
|
'carts.email',
|
|
'carts.total_amount',
|
|
'carts.created_at as date',
|
|
DB::raw("CONCAT(carts.first_name,' ',carts.last_name) as patient_name")
|
|
)
|
|
->where('carts.created_at', '>=', $start_date . " 00:00:00")
|
|
->where('carts.created_at', '<=', $end_date . " 23:59:59");
|
|
|
|
// Apply filters
|
|
if ($status != 'all') {
|
|
$query->where('carts.status', $status);
|
|
}
|
|
|
|
if ($patient != 'all') {
|
|
$query->where('carts.patient_id', $patient);
|
|
}
|
|
$dates = [];
|
|
$sales = [];
|
|
$startDate = Carbon::parse($start_date);
|
|
$endDate = Carbon::parse($end_date);
|
|
for ($date = $startDate; $date->lte($endDate); $date->addDay()) {
|
|
$values = Cart::select(
|
|
DB::raw('DATE(created_at) as date'),
|
|
DB::raw("SUM(carts.total_amount) as amount")
|
|
)
|
|
->where('carts.created_at', '>=', $date->format("Y-m-d") . " 00:00:00")
|
|
->where('carts.created_at', '<=', $date->format("Y-m-d") . " 23:59:59")
|
|
->groupBy(DB::raw('DATE(created_at)'));
|
|
if ($status != 'all') {
|
|
$values->where('carts.status', $status);
|
|
}
|
|
|
|
if ($patient != 'all') {
|
|
$values->where('carts.patient_id', $patient);
|
|
}
|
|
$graphsValues = $values->first();
|
|
|
|
$dates[] = $date->format("M d/y");
|
|
if ($graphsValues)
|
|
$sales[] = $graphsValues->amount;
|
|
else
|
|
$sales[] = 0;
|
|
}
|
|
// dd(Constant::getFullSql($query));
|
|
$orderCollection = $query->get();
|
|
$orderData = $orderCollection->map(function ($cart) {
|
|
$patientType = Cart::where('email', $cart->email)->count();
|
|
|
|
$itemSold = Item::select(DB::raw("GROUP_CONCAT(plans_v1.title SEPARATOR ', ') as items"))
|
|
->where('cart_id', $cart->order_id)
|
|
->leftJoin('plans_v1', 'items.plans_id', 'plans_v1.id');
|
|
$itemCount = $itemSold->count();
|
|
$products = $itemSold->first();
|
|
|
|
$cart->customer_type = $patientType > 1 ? 'returning' : 'new';
|
|
$cart->products = $products->items ?? null;
|
|
$cart->item_sold = $itemCount ?? null;
|
|
$cart->attribution = 'direct';
|
|
|
|
return $cart;
|
|
});
|
|
$totalOrdersStats = Cart::select(
|
|
// DB::raw("sum(case when carts.status = 'delivered' then 1 else 0 end) as total_sales"),
|
|
DB::raw("count(carts.id) as total_sales"),
|
|
DB::raw("sum(carts.total_amount ) as sales_amount"),
|
|
DB::raw("count(items.id) as products_sold")
|
|
)
|
|
->Join('items', 'items.cart_id', 'carts.id')
|
|
->where('carts.created_at', '>=', $start_date . " 00:00:00")
|
|
->where('carts.created_at', '<=', $end_date . " 23:59:59");
|
|
|
|
if ($status != 'all') {
|
|
|
|
$totalOrdersStats->where('carts.status', $status);
|
|
}
|
|
|
|
if ($patient != 'all') {
|
|
$totalOrdersStats->where('carts.patient_id', $patient);
|
|
}
|
|
$totals = $totalOrdersStats->get();
|
|
return response()->json([
|
|
'orders' => $orderData,
|
|
'totals' => $totals,
|
|
'chart' => [
|
|
'chart_dates' => $dates,
|
|
'chart_data' => $sales
|
|
]
|
|
]);
|
|
} catch (AuthorizationException $e) {
|
|
return $e->getMessage();
|
|
}
|
|
}
|
|
public function productAnalytics(Request $request)
|
|
{
|
|
try {
|
|
$this->authorizeForUser($this->user, 'orders_analytics', new ProfileQuestion);
|
|
$start_date = $request->get('start_date');
|
|
$end_date = $request->get('end_date');
|
|
$singleProduct = $request->get('single_product');
|
|
$patient = $request->get('patient');
|
|
$query = Item::select(
|
|
DB::raw("sum(case when items.status='delivered' then items.quantity else 0 end) as total_item_sold"),
|
|
DB::raw("sum(case when items.status='delivered' then 1 else 0 end) as total_orders"),
|
|
DB::raw("sum(case when items.status='delivered' then (items.quantity*plans_v1.price) else 0 end) as total_amount"),
|
|
'plans_v1.title as product_name',
|
|
'items.plans_id as product_id'
|
|
)
|
|
->leftJoin('plans_v1', 'plans_v1.id', 'items.plans_id')
|
|
->where('items.created_at', '>=', $start_date . " 00:00:00")
|
|
->where('items.created_at', '<=', $end_date . " 23:59:59")
|
|
->where('items.status', 'delivered')
|
|
->groupby('plans_v1.title', 'items.plans_id');
|
|
// Apply filters
|
|
if ($singleProduct != 'all') {
|
|
$query->where('items.plans_id', $singleProduct);
|
|
}
|
|
|
|
$dates = [];
|
|
$sales = [];
|
|
$startDate = Carbon::parse($start_date);
|
|
$endDate = Carbon::parse($end_date);
|
|
for ($date = $startDate; $date->lte($endDate); $date->addDay()) {
|
|
$graphsValues = Item::select(
|
|
DB::raw("sum(case when items.status='delivered' then 1 else 0 end) as total_orders"),
|
|
DB::raw("sum(case when items.status='delivered' then (items.quantity*plans_v1.price) else 0 end) as total_amount"),
|
|
)
|
|
->leftJoin('plans_v1', 'plans_v1.id', 'items.plans_id')
|
|
->where('items.created_at', '>=', $date->format("Y-m-d") . " 00:00:00")
|
|
->where('items.created_at', '<=', $date->format("Y-m-d") . " 23:59:59")
|
|
->where('items.status', 'delivered')
|
|
->groupby('plans_v1.title', 'items.plans_id');
|
|
|
|
if ($singleProduct != 'all') {
|
|
$graphsValues->where('items.plans_id', $singleProduct);
|
|
}
|
|
|
|
$graphVal = $graphsValues->first();
|
|
|
|
$dates[] = $date->format("M d/y");
|
|
if ($graphVal)
|
|
$sales[] = $graphVal->total_amount;
|
|
else
|
|
$sales[] = 0;
|
|
}
|
|
$orderData = $query->get();
|
|
$totalOrdersStats = Item::select(
|
|
DB::raw("count(items.id) as total_orders"),
|
|
DB::raw("sum(case when items.status='delivered' then (items.quantity*plans_v1.price) else 0 end) as sales_amount"),
|
|
DB::raw("sum(case when items.status='delivered' then items.quantity else 0 end) as products_sold")
|
|
)
|
|
->leftJoin('plans_v1', 'plans_v1.id', 'items.plans_id')
|
|
->where('items.created_at', '>=', $start_date . " 00:00:00")
|
|
->where('items.created_at', '<=', $end_date . " 23:59:59")
|
|
->where('items.status', 'delivered');
|
|
|
|
if ($singleProduct != 'all') {
|
|
$totalOrdersStats->where('items.plans_id', $singleProduct);
|
|
}
|
|
$totals = $totalOrdersStats->get();
|
|
return response()->json([
|
|
'orders' => $orderData,
|
|
'totals' => $totals,
|
|
'chart' => [
|
|
'chart_dates' => $dates,
|
|
'chart_data' => $sales
|
|
]
|
|
]);
|
|
} catch (AuthorizationException $e) {
|
|
return $e->getMessage();
|
|
}
|
|
}
|
|
public function totalSales()
|
|
{
|
|
$start_date = request()->input('start_date');
|
|
$end_date = request()->input('end_date');
|
|
$startDate = Carbon::parse($start_date);
|
|
$endDate = Carbon::parse($end_date);
|
|
$sales = [];
|
|
for ($date = $startDate; $date->lte($endDate); $date->addDay()) {
|
|
$graphsValues = Item::select(
|
|
DB::raw("sum(case when items.status='delivered' then 1 else 0 end) as total_orders"),
|
|
DB::raw("sum(case when items.status='delivered' then (items.quantity*plans_v1.price) else 0 end) as total_amount"),
|
|
)
|
|
->leftJoin('plans_v1', 'plans_v1.id', 'items.plans_id')
|
|
->where('items.created_at', '>=', $date->format("Y-m-d") . " 00:00:00")
|
|
->where('items.created_at', '<=', $date->format("Y-m-d") . " 23:59:59")
|
|
->where('items.status', 'delivered')
|
|
->groupby('plans_v1.title', 'items.plans_id');
|
|
|
|
$graphVal = $graphsValues->first();
|
|
|
|
$dates[] = $date->format("M d/y");
|
|
if ($graphVal) {
|
|
$sales[$date->format("Y-m-d")] = ["total_amount" => $graphVal->total_amount, "order_count" => $graphVal->total_orders];
|
|
} else {
|
|
$sales[$date->format("Y-m-d")] = ["total_amount" => 0, "order_count" => 0];
|
|
}
|
|
}
|
|
dd($dates, $sales);
|
|
}
|
|
public function ordersAnalytics(Request $request)
|
|
{
|
|
try {
|
|
$this->authorizeForUser($this->user, 'orders_analytics', new ProfileQuestion);
|
|
$start_date = $request->get('start_date');
|
|
$end_date = $request->get('end_date');
|
|
$singleProduct = $request->get('single_product');
|
|
$query = Cart::select(
|
|
'carts.id as order_id',
|
|
"carts.status as order_status",
|
|
"carts.created_at as order_date",
|
|
DB::raw("GROUP_CONCAT(plans_v1.title SEPARATOR ', ') as items"),
|
|
DB::raw("CONCAT(carts.first_name,' ',carts.last_name) as patient_name"),
|
|
"carts.total_amount",
|
|
DB::raw("sum(case when carts.status='completed' then 1 else 0 end) as item_sold")
|
|
)
|
|
->leftJoin('items', 'items.cart_id', 'carts.id')
|
|
->leftJoin('plans_v1', 'plans_v1.id', 'items.plans_id')
|
|
->where('carts.created_at', '>=', $start_date . " 00:00:00")
|
|
->where('carts.created_at', '<=', $end_date . " 23:59:59")
|
|
->where('carts.status', 'completed')
|
|
->groupby('carts.id',
|
|
'carts.status',
|
|
'carts.created_at',
|
|
DB::raw("CONCAT(carts.first_name,' ',carts.last_name)"),
|
|
"carts.total_amount");
|
|
|
|
$dates = [];
|
|
$sales = [];
|
|
$singleMonth = [];
|
|
$current_month = null;
|
|
$graphDates = null;
|
|
$startDate = Carbon::parse($start_date);
|
|
$endDate = Carbon::parse($end_date);
|
|
for ($date = $startDate; $date->lte($endDate); $date->addDay())
|
|
{
|
|
$graphsValues = Cart::select(
|
|
DB::raw('DATE(created_at) as date'),
|
|
DB::raw("SUM(carts.total_amount) as amount")
|
|
)
|
|
->where('carts.created_at', '>=', $date->format("Y-m-d") . " 00:00:00")
|
|
->where('carts.created_at', '<=', $date->format("Y-m-d") . " 23:59:59")
|
|
->where('carts.status', 'completed')
|
|
->groupBy(DB::raw('DATE(created_at)'));
|
|
$graphVal = $graphsValues->first();
|
|
|
|
$month = $date->format('F Y');
|
|
|
|
if ($month != $current_month)
|
|
{
|
|
// Month has changed or it's the first iteration, echo the first day of the month
|
|
$dates[] = $month;
|
|
$current_month = $month;
|
|
} else {
|
|
|
|
$dates[] = " ";
|
|
}
|
|
|
|
$singleMonth[] = $date->format("M d/y");
|
|
|
|
if ($graphVal)
|
|
$sales[] = $graphVal->amount;
|
|
else
|
|
$sales[] = 0;
|
|
}
|
|
// count if user select more then one month
|
|
$dateIterate = $this->monthItrator($start_date, $end_date);
|
|
if ($dateIterate == 1)
|
|
$graphDates = $singleMonth;
|
|
else
|
|
$graphDates = $dates;
|
|
|
|
$orderData = $query->get();
|
|
$totalOrdersStats = Item::select(
|
|
DB::raw("count(items.id) as total_orders"),
|
|
DB::raw("sum(case when items.status='delivered' then (items.quantity*plans_v1.price) else 0 end) as sales_amount"),
|
|
DB::raw("sum(case when items.status='delivered' then items.quantity else 0 end) as products_sold")
|
|
)
|
|
->leftJoin('plans_v1', 'plans_v1.id', 'items.plans_id')
|
|
->where('items.created_at', '>=', $start_date . " 00:00:00")
|
|
->where('items.created_at', '<=', $end_date . " 23:59:59")
|
|
->where('items.status', 'delivered');
|
|
|
|
$totals = $totalOrdersStats->get();
|
|
return response()->json([
|
|
'orders' => $orderData,
|
|
'totals' => $totals,
|
|
'chart' => [
|
|
'chart_dates' => $graphDates,
|
|
'chart_data' => $sales
|
|
]
|
|
]);
|
|
} catch (AuthorizationException $e) {
|
|
return $e->getMessage();
|
|
}
|
|
}
|
|
public function monthItrator($start_date, $end_date)
|
|
{
|
|
|
|
$start = (clone Carbon::parse($start_date))->modify('first day of this month');
|
|
$end = (clone Carbon::parse($end_date))->modify('first day of next month');
|
|
|
|
$interval = DateInterval::createFromDateString('1 month');
|
|
$period = new DatePeriod($start, $interval, $end);
|
|
return iterator_count($period);
|
|
}
|
|
}
|