Commit b29e4e27 authored by DevPilot's avatar DevPilot

fix(sql): second pass on wrong columns and missing tables

جداول ما كانتش موجودة أصلًا (sessions، group_players، training_group_players،
facility_units، activities، membership_types) وكانت أي شاشة أو كرون بيلمسها بيقع.
اتوجّهت للجداول الحقيقية (training_sessions، sa_group_players، sa_facility_units،
sport_disciplines)، وتذكير تجديد العضوية اتعمل على السنة المالية لأن members
مفيهاش تاريخ انتهاء أصلًا. وCustomerPricingService اتكتب من أول وجديد لأن
الربط بالعضو على مستوى الصنف مش على مستوى القائمة.
parent 952aa695
......@@ -229,10 +229,11 @@ final class AchievementEngine
$db = App::getInstance()->db();
$records = $db->select(
"SELECT attendance_date, status
FROM session_attendance
WHERE player_id = ?
ORDER BY attendance_date DESC
"SELECT ts.session_date AS attendance_date, sa.status
FROM session_attendance sa
JOIN training_sessions ts ON ts.id = sa.session_id
WHERE sa.player_id = ?
ORDER BY ts.session_date DESC
LIMIT 100",
[$playerId]
);
......
......@@ -168,10 +168,10 @@ final class AlertProcessorService
$rows = $db->select(
"SELECT tg.id, tg.name_ar, tg.max_capacity,
COUNT(tgp.id) AS current_count
FROM training_groups tg
LEFT JOIN training_group_players tgp ON tgp.group_id = tg.id AND tgp.is_active = 1
WHERE tg.is_active = 1 AND tg.max_capacity > 0
GROUP BY tg.id
FROM sa_groups tg
LEFT JOIN sa_group_players tgp ON tgp.group_id = tg.id AND tgp.status = 'active'
WHERE tg.is_archived = 0 AND tg.max_capacity > 0
GROUP BY tg.id, tg.name_ar, tg.max_capacity
HAVING (current_count / tg.max_capacity * 100) >= ?",
[$threshold]
);
......
......@@ -352,7 +352,7 @@ class FacilityController extends Controller
}
$db = App::getInstance()->db();
$units = $db->select("SELECT id, name_ar FROM facility_units WHERE facility_id = ? AND is_active = 1 ORDER BY name_ar", [(int) $id]);
$units = $db->select("SELECT id, name_ar FROM sa_facility_units WHERE facility_id = ? AND is_active = 1 ORDER BY name_ar", [(int) $id]);
return $this->view('Facilities.Views.timeslots.create', [
'facility' => $facility,
......
......@@ -65,7 +65,7 @@ class AccessControlService
if (!$memberId) return false;
$db = App::getInstance()->db();
$member = $db->selectOne(
"SELECT id, membership_status FROM members WHERE id = ? AND membership_status = 'active'",
"SELECT id, status FROM members WHERE id = ? AND status = 'active'",
[$memberId]
);
return $member !== null && $member !== false;
......
......@@ -40,7 +40,7 @@ class BiometricController extends Controller
$this->authorize('hr.biometric.manage');
$db = App::getInstance()->db();
$branches = $db->select("SELECT id, name_ar FROM branches WHERE is_archived = 0 ORDER BY name_ar");
$branches = $db->select("SELECT id, name_ar FROM branches WHERE is_active = 1 ORDER BY name_ar");
return $this->view('HR.Views.biometric.device_form', [
'device' => null,
......@@ -93,7 +93,7 @@ class BiometricController extends Controller
return $this->redirect('/hr/biometric/devices')->withError('الجهاز غير موجود');
}
$branches = $db->select("SELECT id, name_ar FROM branches WHERE is_archived = 0 ORDER BY name_ar");
$branches = $db->select("SELECT id, name_ar FROM branches WHERE is_active = 1 ORDER BY name_ar");
return $this->view('HR.Views.biometric.device_form', [
'device' => $device,
......
......@@ -88,7 +88,7 @@ class DisciplinaryController extends Controller
$db = App::getInstance()->db();
$decider = $action->decided_by
? $db->selectOne("SELECT name FROM employees WHERE id = ?", [(int) $action->decided_by])
? $db->selectOne("SELECT full_name_ar AS name FROM employees WHERE id = ?", [(int) $action->decided_by])
: null;
return $this->view('HR.Views.disciplinary.show', [
......
......@@ -106,7 +106,7 @@ class EndOfServiceController extends Controller
$db = App::getInstance()->db();
$approver = $record->approved_by
? $db->selectOne("SELECT name FROM employees WHERE id = ?", [(int) $record->approved_by])
? $db->selectOne("SELECT full_name_ar AS name FROM employees WHERE id = ?", [(int) $record->approved_by])
: null;
return $this->view('HR.Views.end_of_service.show', [
......
......@@ -103,7 +103,7 @@ class LeaveController extends Controller
);
$approver = $leaveRequest->approved_by
? $db->selectOne("SELECT name FROM employees WHERE id = ?", [(int) $leaveRequest->approved_by])
? $db->selectOne("SELECT full_name_ar AS name FROM employees WHERE id = ?", [(int) $leaveRequest->approved_by])
: null;
return $this->view('HR.Views.leaves.show', [
......
......@@ -89,7 +89,7 @@ class LoanController extends Controller
$installments = HrLoanInstallment::getForLoan((int) $id);
$approver = $loan['approved_by']
? $db->selectOne("SELECT name FROM employees WHERE id = ?", [(int) $loan['approved_by']])
? $db->selectOne("SELECT full_name_ar AS name FROM employees WHERE id = ?", [(int) $loan['approved_by']])
: null;
return $this->view('HR.Views.loans.show', [
......
......@@ -159,7 +159,7 @@ class PerformanceController extends Controller
: null;
$reviewer = $review->reviewer_id
? $db->selectOne("SELECT name FROM employees WHERE id = ?", [(int) $review->reviewer_id])
? $db->selectOne("SELECT full_name_ar AS name FROM employees WHERE id = ?", [(int) $review->reviewer_id])
: null;
return $this->view('HR.Views.performance.show_review', [
......
......@@ -22,10 +22,13 @@ final class InsuranceCalculationService
}
$salary = $db->selectOne(
"SELECT basic_salary, variable_salary FROM hr_employee_salary_details
WHERE employee_id = ? AND effective_date <= ?
ORDER BY effective_date DESC LIMIT 1",
[$employeeId, $date]
// الراتب الأساسي والمتغير متسجّلين على ملف الموظف.
// بنقبل رقم الملف أو رقم الموظف لأن الاتنين بيتبعتوا من أماكن مختلفة.
"SELECT basic_salary, variable_salary
FROM hr_employee_profiles
WHERE (id = ? OR employee_id = ?) AND is_archived = 0
ORDER BY id DESC LIMIT 1",
[$employeeId, $employeeId]
);
if (!$salary) {
......
......@@ -132,7 +132,7 @@ final class BomService
if (!$bom) return ['total_cost' => '0.00', 'components' => []];
$components = $db->select(
"SELECT bc.*, i.name_ar, i.selling_price,
"SELECT bc.*, i.name_ar, i.sale_price_member,
(SELECT AVG(unit_cost) FROM stock_movements WHERE item_id = bc.component_item_id AND direction = 'in' ORDER BY created_at DESC LIMIT 10) as avg_cost
FROM bom_components bc
JOIN inventory_items i ON i.id = bc.component_item_id
......
......@@ -94,7 +94,7 @@ class ScheduledNotification extends Model
$where = implode(' AND ', $conditions);
$stmt = $db->query(
"UPDATE scheduled_notifications SET status = 'cancelled', updated_at = NOW() WHERE {$where}",
"UPDATE scheduled_notifications SET status = 'cancelled' WHERE {$where}",
$params
);
......
......@@ -117,13 +117,15 @@ final class CronNotificationService
}
$subscriptions = $db->select("
SELECT asub.id AS subscription_id, asub.player_id, asub.next_payment_date,
asub.amount_per_period, p.full_name_ar AS player_name,
SELECT asub.id AS subscription_id, asub.player_id,
asub.due_date AS next_payment_date,
asub.total_amount AS amount_per_period,
p.full_name_ar AS player_name,
p.phone, p.guardian_phone,
a.name_ar AS activity_name
FROM activity_subscriptions asub
JOIN players p ON p.id = asub.player_id
JOIN activities a ON a.id = asub.activity_id
JOIN sport_disciplines a ON a.id = asub.discipline_id
WHERE asub.status = 'active'
AND asub.next_payment_date = ?
AND p.is_archived = 0
......@@ -251,6 +253,20 @@ final class CronNotificationService
return ['processed' => $processed];
}
/** السنة المالية بتبدأ أول يوليو وتنتهي ٣٠ يونيو. */
private static function currentFinancialYear(): string
{
$month = (int) date('n');
$year = (int) date('Y');
return $month >= 7 ? $year . '/' . ($year + 1) : ($year - 1) . '/' . $year;
}
/** آخر يوم في السنة المالية الحالية. */
private static function currentFinancialYearEnd(): string
{
return explode('/', self::currentFinancialYear())[1] . '-06-30';
}
/**
* Check for memberships expiring in 30 days and 7 days.
*/
......@@ -274,17 +290,27 @@ final class CronNotificationService
continue;
}
// العضوية بتنتهي بنهاية السنة المالية (٣٠ يونيو)، مش بتاريخ مخزّن
// على العضو. فالتذكير بيتبعت لما ناقص على النهاية ٣٠ أو ٧ أيام.
$fyEnd = self::currentFinancialYearEnd();
if ($fyEnd !== $targetDate) {
continue;
}
$members = $db->select("
SELECT m.id AS member_id, m.full_name_ar, m.phone_mobile,
m.membership_end_date, mt.name_ar AS membership_type
? AS membership_end_date, m.membership_type
FROM members m
LEFT JOIN membership_types mt ON mt.id = m.membership_type_id
JOIN subscriptions s ON s.member_id = m.id
AND s.financial_year = ?
AND s.person_type = 'member'
AND s.status = 'paid'
WHERE m.is_archived = 0
AND m.status = 'active'
AND m.membership_end_date = ?
AND m.phone_mobile IS NOT NULL
AND m.phone_mobile != ''
", [$targetDate]);
GROUP BY m.id
", [$fyEnd, self::currentFinancialYear()]);
foreach ($members as $member) {
$templateId = $trigger['template_id'] ? (int) $trigger['template_id'] : null;
......@@ -350,7 +376,7 @@ final class CronNotificationService
foreach ($coaches as $coach) {
// Count sessions conducted this month
$sessionCount = $db->selectOne("
SELECT COUNT(*) AS cnt FROM sessions
SELECT COUNT(*) AS cnt FROM training_sessions
WHERE coach_id = ? AND session_date BETWEEN ? AND ? AND status = 'completed'
", [(int) $coach['coach_id'], $firstDayOfMonth, $lastDayOfMonth]);
......@@ -358,7 +384,7 @@ final class CronNotificationService
$playerCount = $db->selectOne("
SELECT COUNT(DISTINCT sa.player_id) AS cnt
FROM session_attendance sa
JOIN sessions s ON s.id = sa.session_id
JOIN training_sessions s ON s.id = sa.session_id
WHERE s.coach_id = ? AND s.session_date BETWEEN ? AND ?
AND sa.status = 'present'
", [(int) $coach['coach_id'], $firstDayOfMonth, $lastDayOfMonth]);
......
......@@ -352,8 +352,8 @@ final class NotificationTriggerService
if ($groupId > 0) {
$players = $db->select(
"SELECT p.id, p.phone
FROM players p
JOIN group_players gp ON gp.player_id = p.id
FROM sa_players p
JOIN sa_group_players gp ON gp.player_id = p.id
WHERE gp.group_id = ? AND gp.status = 'active'
AND p.is_archived = 0 AND p.phone IS NOT NULL AND p.phone != ''",
[$groupId]
......@@ -377,7 +377,7 @@ final class NotificationTriggerService
if ($sessionId > 0) {
// Get group from session then resolve group players
$session = $db->selectOne("SELECT group_id FROM sessions WHERE id = ?", [$sessionId]);
$session = $db->selectOne("SELECT group_id FROM training_sessions WHERE id = ?", [$sessionId]);
if ($session && $session['group_id']) {
$data['group_id'] = (int) $session['group_id'];
return self::resolveGroupPlayersRecipient($db, $data);
......
......@@ -89,12 +89,11 @@ final class MedicalRecordService
]);
}
// Also update sa_players if the player exists there
$saPlayer = $db->selectOne("SELECT id FROM sa_players WHERE player_id = ?", [(int) $record['player_id']]);
if ($saPlayer) {
// نفس التحديث على sa_players لو السجل مربوط بلاعب هناك
if (!empty($record['sa_player_id'])) {
$db->update('sa_players', [
'medical_level' => $medicalLevel,
], 'player_id = ?', [(int) $record['player_id']]);
], 'id = ?', [(int) $record['sa_player_id']]);
}
EventBus::dispatch('player.medical_approved', [
......
......@@ -27,8 +27,10 @@ final class CarnetController extends ApiController
}
$carnet = $db->selectOne(
"SELECT id, carnet_number, total_invitations, used_invitations, status, issued_at
FROM carnets WHERE member_id = ? AND status = 'active'
"SELECT id, carnet_number, total_invitations, used_invitations,
CASE WHEN is_active = 1 THEN 'active' ELSE 'inactive' END AS status,
issued_at
FROM carnets WHERE member_id = ? AND is_active = 1
ORDER BY issued_at DESC LIMIT 1",
[$player->member_id]
);
......@@ -64,7 +66,7 @@ final class CarnetController extends ApiController
}
$carnet = $db->selectOne(
"SELECT id, total_invitations, used_invitations FROM carnets WHERE member_id = ? AND status = 'active' ORDER BY issued_at DESC LIMIT 1",
"SELECT id, total_invitations, used_invitations FROM carnets WHERE member_id = ? AND is_active = 1 ORDER BY issued_at DESC LIMIT 1",
[$player->member_id]
);
......
......@@ -34,7 +34,7 @@ final class ProfileController extends ApiController
$memberInfo = null;
if (!empty($full['member_id'])) {
$memberInfo = $db->selectOne(
"SELECT membership_number, membership_type, membership_status
"SELECT membership_number, membership_type, status
FROM members WHERE id = ?",
[$full['member_id']]
);
......
......@@ -104,9 +104,9 @@ final class SportBrowseController extends ApiController
}
$pricing = $db->selectOne(
"SELECT member_rate, non_member_rate
"SELECT member_rate, nonmember_rate AS non_member_rate
FROM activity_pricing
WHERE entity_type = 'discipline' AND entity_id = ? AND is_active = 1
WHERE pricing_type = 'discipline' AND reference_id = ? AND is_active = 1
AND (effective_from IS NULL OR effective_from <= CURDATE())
AND (effective_to IS NULL OR effective_to >= CURDATE())
ORDER BY effective_from DESC LIMIT 1",
......
......@@ -61,7 +61,7 @@ class QuoteController extends Controller
}
$suppliers = $db->select("SELECT id, name_ar, code FROM suppliers WHERE is_archived = 0 AND is_active = 1 ORDER BY name_ar");
$requisitions = $db->select("SELECT id, requisition_number, status FROM purchase_requisitions WHERE status = 'approved' ORDER BY created_at DESC LIMIT 50");
$requisitions = $db->select("SELECT id, pr_number AS requisition_number, status FROM purchase_requisitions WHERE status = 'approved' ORDER BY created_at DESC LIMIT 50");
return $this->view('Procurement.Views.quotes.request_form', [
'requisition' => $requisition,
......
......@@ -21,8 +21,8 @@ final class PlayerRetentionReportService
// Total active players at start of period
$activeAtStart = $db->selectOne(
"SELECT COUNT(DISTINCT tgp.player_id) AS cnt
FROM training_group_players tgp
WHERE tgp.joined_at < ?
FROM sa_group_players tgp
WHERE tgp.enrolled_at < ?
AND (tgp.left_at IS NULL OR tgp.left_at >= ?)",
[$periodFrom, $periodFrom]
);
......@@ -31,8 +31,8 @@ final class PlayerRetentionReportService
// New enrollments during period
$newEnrollments = $db->selectOne(
"SELECT COUNT(DISTINCT tgp.player_id) AS cnt
FROM training_group_players tgp
WHERE tgp.joined_at BETWEEN ? AND ?",
FROM sa_group_players tgp
WHERE tgp.enrolled_at BETWEEN ? AND ?",
[$periodFrom, $periodTo]
);
$newCount = (int) ($newEnrollments['cnt'] ?? 0);
......@@ -40,7 +40,7 @@ final class PlayerRetentionReportService
// Dropped during period (left_at within range)
$dropped = $db->selectOne(
"SELECT COUNT(DISTINCT tgp.player_id) AS cnt
FROM training_group_players tgp
FROM sa_group_players tgp
WHERE tgp.left_at BETWEEN ? AND ?",
[$periodFrom, $periodTo]
);
......@@ -49,8 +49,8 @@ final class PlayerRetentionReportService
// Active at end of period
$activeAtEnd = $db->selectOne(
"SELECT COUNT(DISTINCT tgp.player_id) AS cnt
FROM training_group_players tgp
WHERE tgp.joined_at <= ?
FROM sa_group_players tgp
WHERE tgp.enrolled_at <= ?
AND (tgp.left_at IS NULL OR tgp.left_at > ?)",
[$periodTo, $periodTo]
);
......@@ -72,23 +72,23 @@ final class PlayerRetentionReportService
COALESCE(new_t.cnt, 0) AS new_enrollments,
COALESCE(drop_t.cnt, 0) AS dropped
FROM (
SELECT DISTINCT DATE_FORMAT(joined_at, '%Y-%m-01') AS month_date
FROM training_group_players
WHERE joined_at BETWEEN ? AND ?
SELECT DISTINCT DATE_FORMAT(enrolled_at, '%Y-%m-01') AS month_date
FROM sa_group_players
WHERE enrolled_at BETWEEN ? AND ?
UNION
SELECT DISTINCT DATE_FORMAT(left_at, '%Y-%m-01') AS month_date
FROM training_group_players
FROM sa_group_players
WHERE left_at BETWEEN ? AND ?
) dates
LEFT JOIN (
SELECT DATE_FORMAT(joined_at, '%Y-%m-01') AS m, COUNT(DISTINCT player_id) AS cnt
FROM training_group_players
WHERE joined_at BETWEEN ? AND ?
SELECT DATE_FORMAT(enrolled_at, '%Y-%m-01') AS m, COUNT(DISTINCT player_id) AS cnt
FROM sa_group_players
WHERE enrolled_at BETWEEN ? AND ?
GROUP BY m
) new_t ON new_t.m = dates.month_date
LEFT JOIN (
SELECT DATE_FORMAT(left_at, '%Y-%m-01') AS m, COUNT(DISTINCT player_id) AS cnt
FROM training_group_players
FROM sa_group_players
WHERE left_at BETWEEN ? AND ?
GROUP BY m
) drop_t ON drop_t.m = dates.month_date
......@@ -99,12 +99,12 @@ final class PlayerRetentionReportService
// By academy breakdown
$byAcademy = $db->select(
"SELECT a.id, a.name_ar,
COUNT(DISTINCT CASE WHEN tgp.joined_at BETWEEN ? AND ? THEN tgp.player_id END) AS new_enrollments,
COUNT(DISTINCT CASE WHEN tgp.enrolled_at BETWEEN ? AND ? THEN tgp.player_id END) AS new_enrollments,
COUNT(DISTINCT CASE WHEN tgp.left_at BETWEEN ? AND ? THEN tgp.player_id END) AS dropped,
COUNT(DISTINCT CASE WHEN (tgp.left_at IS NULL OR tgp.left_at > ?) AND tgp.joined_at <= ? THEN tgp.player_id END) AS active_now
COUNT(DISTINCT CASE WHEN (tgp.left_at IS NULL OR tgp.left_at > ?) AND tgp.enrolled_at <= ? THEN tgp.player_id END) AS active_now
FROM training_groups tg
LEFT JOIN academies a ON a.id = tg.academy_id
LEFT JOIN training_group_players tgp ON tgp.group_id = tg.id
LEFT JOIN sa_group_players tgp ON tgp.group_id = tg.id
WHERE a.id IS NOT NULL
GROUP BY a.id, a.name_ar
HAVING new_enrollments > 0 OR dropped > 0 OR active_now > 0
......
......@@ -5,6 +5,13 @@ namespace App\Modules\Sales\Services;
use App\Core\App;
/**
* أسعار خاصة لعميل معيّن.
*
* ملحوظة على الـ schema: قايمة الأسعار (customer_price_lists) هي مجرد غلاف
* بالاسم وفترة السريان، والربط بالعضو وبالسعر نفسه على مستوى الصنف في
* customer_item_prices (member_id + item_id + special_price).
*/
final class CustomerPricingService
{
public static function getPrice(int $itemId, ?int $memberId = null): ?string
......@@ -14,35 +21,37 @@ final class CustomerPricingService
$db = App::getInstance()->db();
$customPrice = $db->selectOne(
"SELECT cip.price
"SELECT cip.special_price
FROM customer_item_prices cip
JOIN customer_price_lists cpl ON cpl.id = cip.price_list_id
WHERE cip.item_id = ? AND cpl.member_id = ? AND cpl.is_active = 1
ORDER BY cip.id DESC LIMIT 1",
LEFT JOIN customer_price_lists cpl ON cpl.id = cip.price_list_id
WHERE cip.item_id = ?
AND cip.member_id = ?
AND cip.is_active = 1
AND cip.special_price IS NOT NULL
AND (cip.start_date IS NULL OR cip.start_date <= CURDATE())
AND (cip.end_date IS NULL OR cip.end_date >= CURDATE())
AND (cpl.id IS NULL OR cpl.is_active = 1)
ORDER BY cip.id DESC
LIMIT 1",
[$itemId, $memberId]
);
return $customPrice ? (string) $customPrice['price'] : null;
return $customPrice ? (string) $customPrice['special_price'] : null;
}
public static function getPriceList(int $memberId): array
{
$db = App::getInstance()->db();
$list = $db->selectOne(
"SELECT * FROM customer_price_lists WHERE member_id = ? AND is_active = 1 ORDER BY id DESC LIMIT 1",
[$memberId]
);
if (!$list) return [];
return $db->select(
"SELECT cip.*, i.name_ar, i.selling_price as default_price
"SELECT cip.*,
i.name_ar,
i.sale_price_member AS default_price
FROM customer_item_prices cip
JOIN inventory_items i ON i.id = cip.item_id
WHERE cip.price_list_id = ?
WHERE cip.member_id = ? AND cip.is_active = 1
ORDER BY i.name_ar",
[(int) $list['id']]
[$memberId]
);
}
......@@ -51,27 +60,34 @@ final class CustomerPricingService
$db = App::getInstance()->db();
$employee = App::getInstance()->currentEmployee();
$db->query("UPDATE customer_price_lists SET is_active = 0 WHERE member_id = ?", [$memberId]);
// الأسعار القديمة بتتوقف مش بتتمسح، عشان يفضل في أثر لأي سعر اتطبّق قبل كده
$db->query("UPDATE customer_item_prices SET is_active = 0 WHERE member_id = ?", [$memberId]);
$listId = $db->insert('customer_price_lists', [
'member_id' => $memberId,
'name_ar' => 'قائمة أسعار خاصة',
'name_ar' => 'قائمة أسعار خاصة' . ($notes ? ' — ' . $notes : ''),
'discount_type' => 'fixed_price',
'notes' => $notes,
'discount_value' => '0.00',
'priority' => 1,
'start_date' => date('Y-m-d'),
'is_active' => 1,
'created_by' => $employee ? (int) $employee->id : null,
'created_at' => date('Y-m-d H:i:s'),
]);
foreach ($items as $item) {
$db->insert('customer_item_prices', [
'member_id' => $memberId,
'price_list_id' => $listId,
'item_id' => (int) $item['item_id'],
'price' => (string) $item['price'],
'min_quantity' => $item['min_quantity'] ?? '1.000',
'discount_type' => 'fixed_price',
'special_price' => (string) $item['price'],
'start_date' => date('Y-m-d'),
'is_active' => 1,
'created_at' => date('Y-m-d H:i:s'),
]);
}
unset($employee);
return $listId;
}
}
......@@ -30,7 +30,7 @@ final class ScheduleConflictResolver
$facilityConflict = $db->selectOne("
SELECT id FROM training_groups
WHERE facility_id = ? AND day_of_week = ? AND status = 'active'
WHERE facility_id = ? AND day_of_week = ? AND is_active = 1
AND (start_time < ? AND end_time > ?)
", [$facilityId, $dayOfWeek, $slotEnd, $slotStart]);
......
......@@ -115,20 +115,34 @@ final class SaEventListenerService
], 'id = ?', [(int) $gameTicket['id']]);
}
$poolTicket = $db->selectOne("SELECT id FROM sa_pool_tickets WHERE payment_id = ?", [$paymentId]);
// تذاكر وحجوزات حمام السباحة مربوطة بطلب الدفع مش بالدفعة نفسها،
// فبنوصل للدفعة من خلال طلب الدفع.
$poolTicket = $db->selectOne(
"SELECT pt.id
FROM sa_pool_tickets pt
JOIN payment_requests pr ON pr.id = pt.payment_request_id
WHERE pr.payment_id = ?",
[$paymentId]
);
if ($poolTicket) {
$db->update('sa_pool_tickets', [
'payment_status' => SaConstants::PAYMENT_UNPAID,
'payment_id' => null,
'payment_request_id' => null,
'updated_at' => date('Y-m-d H:i:s'),
], 'id = ?', [(int) $poolTicket['id']]);
}
$poolRes = $db->selectOne("SELECT id FROM sa_pool_reservations WHERE payment_id = ?", [$paymentId]);
$poolRes = $db->selectOne(
"SELECT prs.id
FROM sa_pool_reservations prs
JOIN payment_requests pr ON pr.id = prs.payment_request_id
WHERE pr.payment_id = ?",
[$paymentId]
);
if ($poolRes) {
$db->update('sa_pool_reservations', [
'payment_status' => 'pending',
'payment_id' => null,
'payment_request_id' => null,
'updated_at' => date('Y-m-d H:i:s'),
], 'id = ?', [(int) $poolRes['id']]);
}
......
......@@ -22,8 +22,9 @@ final class CoachProfileController extends ApiController
$db = App::getInstance()->db();
$full = $db->selectOne(
"SELECT id, name_ar, name_en, phone, email, employment_type, payment_model,
session_rate, monthly_salary, certifications_json, session_types_json,
"SELECT id, full_name_ar AS name_ar, full_name_en AS name_en, phone, email,
employment_type, payment_model,
session_rate, monthly_rate AS monthly_salary, certifications_json,
is_active, created_at
FROM coaches WHERE id = ?",
[$coach->id]
......
......@@ -20,7 +20,7 @@ class SessionFeedbackController extends Controller
$this->authorize('training.submit_feedback');
$db = App::getInstance()->db();
$session = $db->selectOne("SELECT * FROM sessions WHERE id = ?", [(int) $sessionId]);
$session = $db->selectOne("SELECT * FROM training_sessions WHERE id = ?", [(int) $sessionId]);
if (!$session) {
return $this->redirect('/sessions')->withError('الحصة غير موجودة');
......@@ -78,7 +78,7 @@ class SessionFeedbackController extends Controller
$this->authorize('training.view_feedback');
$db = App::getInstance()->db();
$session = $db->selectOne("SELECT * FROM sessions WHERE id = ?", [(int) $sessionId]);
$session = $db->selectOne("SELECT * FROM training_sessions WHERE id = ?", [(int) $sessionId]);
if (!$session) {
return $this->redirect('/sessions')->withError('الحصة غير موجودة');
......
......@@ -85,7 +85,7 @@ class SessionFeedbackService
SUM(CASE WHEN sf.energy_level = 'medium' THEN 1 ELSE 0 END) as energy_medium,
SUM(CASE WHEN sf.energy_level = 'low' THEN 1 ELSE 0 END) as energy_low
FROM session_feedback sf
INNER JOIN sessions s ON s.id = sf.session_id
INNER JOIN training_sessions s ON s.id = sf.session_id
WHERE s.coach_id = ?
AND s.session_date BETWEEN ? AND ?",
[$coachId, $dateFrom, $dateTo]
......@@ -95,7 +95,7 @@ class SessionFeedbackService
"SELECT s.id, s.session_date, s.start_time,
COUNT(sf.id) as feedback_count,
AVG(sf.rating) as avg_rating
FROM sessions s
FROM training_sessions s
INNER JOIN session_feedback sf ON sf.session_id = s.id
WHERE s.coach_id = ?
AND s.session_date BETWEEN ? AND ?
......@@ -123,7 +123,7 @@ class SessionFeedbackService
AVG(sf.rating) as avg_rating,
AVG(sf.enjoyment_level) as avg_enjoyment,
AVG(sf.difficulty_level) as avg_difficulty
FROM sessions s
FROM training_sessions s
INNER JOIN session_feedback sf ON sf.session_id = s.id
WHERE s.group_id = ?
GROUP BY s.session_date
......
......@@ -46,7 +46,7 @@ class GroupTransferService
$group = $db->selectOne("SELECT * FROM training_groups WHERE id = ?", [$toGroupId]);
if ($group && $group['max_capacity']) {
$currentCount = (int) $db->selectOne(
"SELECT COUNT(*) AS c FROM group_players WHERE group_id = ? AND is_active = 1",
"SELECT COUNT(*) AS c FROM sa_group_players WHERE group_id = ? AND status = 'active'",
[$toGroupId]
)['c'];
......@@ -80,18 +80,18 @@ class GroupTransferService
'updated_at' => date('Y-m-d H:i:s'),
], '`id` = ?', [$requestId]);
$db->update('group_players', ['is_active' => 0, 'updated_at' => date('Y-m-d H:i:s')], '`group_id` = ? AND `player_id` = ?', [(int) $request['from_group_id'], (int) $request['player_id']]);
$db->update('sa_group_players', ['status' => 'left', 'left_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s')], '`group_id` = ? AND `player_id` = ?', [(int) $request['from_group_id'], (int) $request['player_id']]);
if ($toGroupId) {
$exists = $db->selectOne("SELECT id FROM group_players WHERE group_id = ? AND player_id = ?", [$toGroupId, (int) $request['player_id']]);
$exists = $db->selectOne("SELECT id FROM sa_group_players WHERE group_id = ? AND player_id = ?", [$toGroupId, (int) $request['player_id']]);
if ($exists) {
$db->update('group_players', ['is_active' => 1, 'updated_at' => date('Y-m-d H:i:s')], '`group_id` = ? AND `player_id` = ?', [$toGroupId, (int) $request['player_id']]);
$db->update('sa_group_players', ['status' => 'active', 'left_at' => null, 'updated_at' => date('Y-m-d H:i:s')], '`group_id` = ? AND `player_id` = ?', [$toGroupId, (int) $request['player_id']]);
} else {
$db->insert('group_players', [
$db->insert('sa_group_players', [
'group_id' => $toGroupId,
'player_id' => (int) $request['player_id'],
'is_active' => 1,
'joined_at' => date('Y-m-d H:i:s'),
'status' => 'active',
'enrolled_at' => date('Y-m-d H:i:s'),
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment