WindowsService - Structure Analysis¶
Executive Summary¶
The Psyter Payment Inquiry Service is a well-structured Windows Service with clear separation of concerns across Data Access Layer (DAL), Data Transfer Objects (DTOs), and service logic. The architecture follows traditional layered patterns with timer-based background processing for payment reconciliation and notification delivery.
Directory Structure¶
WindowsService/
├── PsyterPaymentInquiry/ # Main service project
│ ├── DAL/ # Data Access Layer
│ │ ├── DBConstants.cs # 14 stored procedure constants
│ │ ├── DBHelper.cs # Base class with data mapping utilities
│ │ ├── PaymentDataAccess.cs # 11 data access methods
│ │ └── XmlHelper.cs # XML serialization helper
│ ├── DTO/ # Data Transfer Objects
│ │ ├── AppConfigSetting.cs # Application configuration models
│ │ ├── FCMNotificationModal.cs # 6 notification/reminder models
│ │ ├── InquiryPayment.cs # 11 payment processing models
│ │ ├── PendingPaymentModal.cs # 5 pending payment models
│ │ └── PsyterAPIAuth.cs # API authentication models
│ ├── Properties/
│ │ └── AssemblyInfo.cs # Assembly metadata
│ ├── App.config # Configuration (DB, APIs, URLs)
│ ├── packages.config # NuGet dependencies
│ ├── PaymentInquiryService.cs # Core service logic (1000+ lines)
│ ├── PaymentInquiryService.Designer.cs
│ ├── Program.cs # Service entry point
│ ├── ProjectInstaller.cs # Windows Service installer
│ ├── ProjectInstaller.Designer.cs
│ └── ProjectInstaller.resx
├── Psyter Payment Inquiry Service/ # Installer project
│ ├── Psyter Payment Inquiry Service.aip # Advanced Installer project
│ └── Setup Files/
├── packages/ # NuGet package binaries
│ ├── Microsoft.Practices.EnterpriseLibrary.Common.dll.3.1.0/
│ ├── Microsoft.Practices.EnterpriseLibrary.Data.dll.3.1.0/
│ ├── Microsoft.Practices.ObjectBuilder.dll.3.1.0/
│ └── Newtonsoft.Json.13.0.1/
└── PsyterPaymentInquiry.sln # Visual Studio solution file
Architecture Overview¶
Layered Architecture¶
┌─────────────────────────────────────────────────┐
│ Windows Service Host │
│ │
│ ┌────────────────────────────────────────────┐ │
│ │ PaymentInquiryService │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌─────────┐ │ │
│ │ │ Timer1 │ │ Timer2 │ │ Timer3 │ │ │
│ │ │ Payment │ │ FCM │ │ SCHFS │ │ │
│ │ │ (10m) │ │ (10m) │ │ (24h) │ │ │
│ │ └────┬─────┘ └────┬─────┘ └────┬────┘ │ │
│ │ │ │ │ │ │
│ │ v v v │ │
│ │ ┌──────────────────────────────────────┐│ │
│ │ │ Thread Management Layer ││ │
│ │ └────────────────┬─────────────────────┘│ │
│ │ │ │ │
│ │ v │ │
│ │ ┌──────────────────────────────────────┐│ │
│ │ │ Business Logic Layer ││ │
│ │ │ - Payment Inquiry ││ │
│ │ │ - Refund Processing ││ │
│ │ │ - Notification Sending ││ │
│ │ │ - Secure Hash Generation ││ │
│ │ └────────────────┬─────────────────────┘│ │
│ └─────────────────────┼──────────────────────┘ │
└────────────────────────┼────────────────────────┘
│
┌───────────────┼───────────────┐
│ │ │
v v v
┌─────────────────┐ ┌─────────────┐ ┌──────────────┐
│ Data Access │ │ External │ │ File I/O │
│ Layer │ │ APIs │ │ (Logging) │
│ │ │ │ │ │
│ ┌─────────────┐ │ │ ┌─────────┐ │ │ ┌──────────┐ │
│ │PaymentData │ │ │ │ Psyter │ │ │ │ Logs/ │ │
│ │ Access │ │ │ │ API │ │ │ │ *.txt │ │
│ └─────────────┘ │ │ └─────────┘ │ │ └──────────┘ │
│ ┌─────────────┐ │ │ ┌─────────┐ │ │ │
│ │ DBHelper │ │ │ │Scheduling│ │ │ │
│ │ │ │ │ │ API │ │ │ │
│ └─────────────┘ │ │ └─────────┘ │ │ │
│ ┌─────────────┐ │ │ ┌─────────┐ │ │ │
│ │ XmlHelper │ │ │ │ Payment │ │ │ │
│ │ │ │ │ │ Gateway │ │ │ │
│ └─────────────┘ │ │ └─────────┘ │ │ │
└─────────────────┘ └─────────────┘ └──────────────┘
│
v
┌─────────────────────────────────┐
│ SQL Server Database │
│ │
│ - Pending Payment Records │
│ - App Configuration Settings │
│ - User Notifications │
│ - Appointment Reminders │
│ - Payment Transaction History │
└─────────────────────────────────┘
Component Interaction Flow¶
Service Start
│
├──> Initialize 4 Timers
│ │
│ ├──> timer (Payment Inquiry/Refund) - 10 minutes
│ ├──> timerForDeleteLogFiles - 15 days
│ ├──> timerNotifySCHFSCardExpiry - 24 hours
│ └──> timerSendFCMNotification - 10 minutes
│
└──> Write startup logs
│
└──> Wait for timer events
│
├──> OnElapsedTime()
│ │
│ └──> CreateThread()
│ │
│ └──> GetPendingPayment()
│ ├──> Process Booking Payments
│ ├──> Process Refunds
│ ├──> Process Wallet Purchases
│ └──> Process Package Purchases
│
├──> OnElapsedTimeForFCMNotificationsAndReminders()
│ │
│ └──> CreateThreadForSendFCMNotificationsAndReminders()
│ │
│ └──> GetPendingFCMNotificationsAndReminders()
│
├──> OnElapsedTimeNotifySCHFSExpiry()
│ │
│ └──> CallNotifySCHFSExpiryAPI()
│
└──> OnElapsedTime30Days()
│
└──> DeleteLogFilesOfPreviousMonth()
Data Access Layer (DAL)¶
DBHelper.cs¶
Purpose: Base database helper class with generic data mapping utilities
Key Features:
- Enterprise Library Database wrapper
- Generic DataTable to Object/List mapping
- Query string parsing utility
- Uses reflection for automatic property mapping
Methods:
+ MapDataTableToList<T>(DataTable) : IList<T>
+ MapDataTableToObject<T>(DataTable) : T
+ ParseQueryString(string) : NameValueCollection
Extension Methods:
DataRowExtention.Fill<T>(DataRow, ref T obj)
PaymentDataAccess.cs¶
Purpose: Concrete implementation for payment-related database operations
Methods (11 total):
| Method | Stored Procedure | Purpose |
|---|---|---|
GETPendingPayments() |
ws_GetPendingPaymentsList_AppConfigSetting | Fetch pending booking payments |
GETPendingForRefundPayments() |
ws_GetPendingPaymentsListForRefund_AppConfigSetting | Fetch pending refund requests |
GETPendingWalletPurchasePayments() |
ws_GetPendingWalletPurchasesList_AppConfigSetting | Fetch pending wallet recharges |
GETPendingPackagePurchasePayments() |
ws_GetPendingPackagePaymentsList_AppConfigSetting | Fetch pending package purchases |
UpdateBookingOrderPayForData() |
ws_UpdatePaymentInquiryStatus | Update booking payment status |
UpdateBookingRefundStatus() |
ws_UpdatePendingPaymentRefundStatus | Update refund status |
UpdateWalletPurchasePayForData() |
ws_UpdateWalletPurchasePaymentInquiryStatus | Update wallet payment status |
UpdatePackagePurchasePayForData() |
ws_UpdatePackagePaymentInquiryStatus | Update package payment status |
GetPsyterApplicationToken() |
AppConfig_GetAppConfigSettingsByGroupId | Retrieve API authentication token |
GetPendingFCMNotificationsAndRemindersToSend() |
Notification_GetNotificationsListToSentUsingFCM | Fetch pending notifications |
MarkFCMNotificationSent() |
Notification_UpdateNotificationSentStatus | Mark notification as sent |
MarkReminderSent() |
Reminder_UpdateReminderSentStatus | Mark reminder as sent |
GetUserRemindersList() |
Reminder_GetUserReminderList | Get user’s reminder list |
Return Patterns:
- Complex objects with nested lists
- Uses DataSet with multiple tables
- Returns boolean for update operations
- Includes output parameters for status codes
DBConstants.cs¶
Purpose: Centralized stored procedure name constants
Constants (14 total):
GET_PENDING_PAYMENTS
GET_PENDING_REFUND_PAYMENTS
GET_PENDING_WALLET_PURCHASE_PAYMENTS
GET_PENDING_PACKAGE_PURCHASE_PAYMENTS
UPDATE_PENDING_PAYMENTS_STATUS
UPDATE_PENDING_REFUND_PAYMENTS_STATUS
UPDATE_WALLET_PURCHASE_PENDING_PAYMENTS_STATUS
UPDATE_PACKAGE_PURCHASE_PENDING_PAYMENTS_STATUS
GET_APPLICATION_CONFIG_BY_GROUP_ID
GET_PENDING_NOTIFICATIONS_FOR_FCM
UPDATE_NOTIFICATIONS_SENT_STATUS
UPDATE_REMINDER_SENT_STATUS
GET_USER_REMINDERS_LIST
XmlHelper.cs¶
Purpose: XML serialization utilities for database parameters
Usage Pattern:
var xml = XmlHelper.ObjectToXml(updateBookingPayForDataObj);
dataBase.AddInParameter(dbCommand, "@PaymentData", DbType.Xml, xml);
Data Transfer Objects (DTOs)¶
Payment Processing Models (InquiryPayment.cs)¶
11 Models:
- RequestRefund - Refund request parameters
- RequestSecureHash - Secure hash generation input
- SecureHashResponse - Generated hash output
- RequestProcessInquiry - Payment inquiry/refund request
- ProcessResponse - Gateway response wrapper
- UpdateScheduleBookingStatusRequest - Booking status update request
- UpdateBookingStatus - Individual booking status update
- BookingStatusUpdateResponseWrapper - API response wrapper
- BookingStatusUpdateResponse - Update response data
- BookingStatusUpdateInfoResponse - Individual update result
- ApplicationConfiguration - App config setting model
Pending Payment Models (PendingPaymentModal.cs)¶
5 Models:
-
GetPendingPaymentsListResponse - Database query result wrapper
+ List<PendingPayment> PendingPaymentsList + List<ApplicationConfiguration> AppConfigSettingList + string ApplicationAPIToken -
PendingPaymentResponse - Service layer response
+ List<PendingPayment> PendingPaymentsList + PaymentApplicationConfiguration AppConfigSetting -
PendingPayment - Individual pending payment details
+ TransactionId, OrderId, PayForDataId + SlotBookingId, ConsumerId, PhysicianId + TotalAmount, PaymentStatus, InquiryCount + UserWalletId, ClientPackageMainId -
UpdateBookingOrderPayForData - Payment update parameters
+ Card details (name, number, expiry) + Gateway response (name, status codes, RRN) + Status codes and descriptions -
UpdateBookingRefundRequestData - Refund update parameters
FCM Notification Models (FCMNotificationModal.cs)¶
6 Models:
-
UserNotification - Simple notification
+ Id, ForUserLoginInfoId + NotificationTitle, NotificationBody + FCMTopic -
UserReminder - Appointment reminder
+ Reminder details (title, text, datetime) + Booking information (SlotBookingId, VideoSDKMeetingId) + Patient details (name, image, ID) + Provider details (name, image, ID) + CatCommunicationTypeId -
UserReminderForFCMPayLoad - Reminder list item for FCM
- FCMConfiguration - FCM API settings
- UserNotificationsListWrapper - Notification query result
- SendCustomFCMNotification - FCM send request
API Authentication Models (PsyterAPIAuth.cs)¶
Model:
public class APIAuthTokenResponse
{
public string AccessToken { get; set; }
public string RefreshToken { get; set; }
public string TokenExpiresIn { get; set; }
}
Configuration Models (AppConfigSetting.cs)¶
Model:
public class PaymentApplicationConfiguration
{
+ SmartRoutingSecretKey
+ SmartRoutingResponseBackURL
+ RedirectToPaymentMobileToken
+ SmartRoutingRedirectURL
+ SmartRoutingMerchantId
+ SmartRoutingCurrencyISOCode
+ SmartRoutingRefundInquiryUrl
+ SmartRoutingThemeId
+ SmartRoutingVersion
+ SmartRoutingItemId
}
Service Implementation (PaymentInquiryService.cs)¶
Class Structure¶
Timers (4):
System.Timers.Timer timer // Payment inquiry/refund
System.Timers.Timer timerForDeleteLogFiles // Log cleanup
System.Timers.Timer timerNotifySCHFSCardExpiry // SCHFS notifications
System.Timers.Timer timerSendFCMNotification // FCM notifications
Threads (4):
Thread RefundAndInquiryThread
Thread DeleteLogFilesThread
Thread NotifySCHFSCardExpiryThread
Thread SendFCMNotifications
Properties:
protected string PsyterAPIApplicationToken
protected string PsyterAPIAuthToken
protected string SchedulingAPIApplicationToken
protected string SchedulingAPIAuthToken
Key Methods¶
Service Lifecycle¶
OnStart(string[] args)
- Initialize timers with intervals
- Enable all timers
- Write startup logs
OnStop()
- Write shutdown logs
Timer Event Handlers¶
OnElapsedTime(object, ElapsedEventArgs)
- 10-minute interval
- Creates RefundAndInquiryThread
- Processes payments and refunds
OnElapsedTime30Days(object, ElapsedEventArgs)
- 15-day interval
- Creates DeleteLogFilesThread
- Deletes logs older than 30 days
OnElapsedTimeNotifySCHFSExpiry(object, ElapsedEventArgs)
- 24-hour interval
- Creates NotifySCHFSCardExpiryThread
- Calls SCHFS expiry notification API
OnElapsedTimeForFCMNotificationsAndReminders(object, ElapsedEventArgs)
- 10-minute interval
- Creates SendFCMNotifications thread
- Sends pending notifications/reminders
Thread Management¶
CreateThread()
- Checks if RefundAndInquiryThread is null or terminated
- Creates new thread if needed
- Logs thread state
CreateThreadForDeleteLogFiles()
CreateThreadForNotifySCHFSExpiry()
CreateThreadForSendFCMNotificationsAndReminders()
- Similar pattern for specialized threads
Payment Processing¶
GetPendingPayment() : async Task<PendingPaymentResponse>
- Fetch pending payments from DB
- Retrieve payment gateway config
- Loop through each payment:
+ Generate secure hash
+ Send inquiry to gateway
+ Parse response
+ Update database
+ Update booking status if successful
- Call GetPendingRefundPayment()
- Call GetPendingWalletPurchasedPayment()
- Call GetPendingPackagePurchasedPayment()
GetPendingRefundPayment() : async Task<PendingPaymentResponse>
- Fetch pending refunds
- Generate refund transaction IDs
- Process refunds through gateway
- Send refund notifications
GetPendingWalletPurchasedPayment() : async Task<PendingPaymentResponse>
- Process wallet recharge inquiries
GetPendingPackagePurchasedPayment() : async Task<PendingPaymentResponse>
- Process package purchase inquiries
Security & Gateway Integration¶
GenerateSecureHash(RequestSecureHash, PaymentApplicationConfiguration) : SecureHashResponse
- Build sorted dictionary of parameters
- Create ordered string with secret key
- Compute SHA256 hash
- Return hex-encoded hash
ProcessInquiryOrRefund(RequestProcessInquiry, PaymentApplicationConfiguration, PendingPayment) : async Task<ProcessResponse>
- Build NameValueCollection for gateway request
- POST to payment gateway
- Parse response
- Update database based on status
Status Update Methods¶
UpdatePaymentInquiryStatus(RequestProcessInquiry, SortedDictionary, PendingPayment) : async Task
- Build UpdateBookingOrderPayForData object
- Authenticate with Scheduling API
- If successful (00000):
+ Update booking status to "Booked" (status 1)
- If failed after 3 attempts:
+ Cancel booking (status 8)
- Update PayForData record
UpdateBookingRefundRequestData(...)
- Update refund status
- Send refund notification
UpdateWalletPurchasePaymentInquiryStatus(...)
- Update wallet purchase status
UpdatePackagePurchasePaymentInquiryStatus(...)
- Update package purchase status
API Integration¶
PsyterApiAuthenticationToken(string) : async Task<APIAuthTokenResponse>
- Authenticate with Psyter API
- Return access token, refresh token, expiry
SchedulingApiAuthenticationToken(string) : async Task<APIAuthTokenResponse>
- Authenticate with Scheduling API
UpdateBookingStatusInScheduling(string) : async Task<JObject>
- Call Scheduling API to update booking status
- Return response as JObject
CallRefundNotificationAPI(string) : async Task<JObject>
- Send refund notification via Psyter API
CallNotifySCHFSExpiryAPI() : async Task
- Authenticate with Psyter API
- Call SCHFS card expiry notification endpoint
CallSendFCMNotificationCommonAPI(string, string) : async Task
- Send FCM notification via Psyter API
- Used for appointment reminders
Notification Processing¶
GetPendingFCMNotificationsAndReminders() : void
- Fetch pending notifications/reminders from DB
- For each reminder:
+ Build FCM payload with user/booking details
+ Call CallSendFCMNotificationCommonAPI()
+ Mark as sent in database
- Handles both patient (UserType=1) and provider (UserType=0) reminders
Utility Methods¶
WriteToFile(string Message, string logType) : void
- Create Logs directory if not exists
- Create daily log file if not exists
- Append message with timestamp
DeleteLogFilesOfPreviousMonth() : void
- Get all files in Logs directory
- Delete files older than 30 days
- Skip DeleteFileLog files
- Log each deletion
AllwaysGoodCertificate(...) : bool
- Accept all SSL certificates (for development)
- Returns true for all certificates
Business Logic Flow¶
Payment Inquiry Flow¶
Timer (10 min) → OnElapsedTime()
↓
CreateThread()
↓
GetPendingPayment()
↓
┌─────────────────┴─────────────────┐
│ │
│ 1. Fetch from DB: │
│ - PendingPaymentsList │
│ - AppConfigSettingList │
│ - ApplicationAPIToken │
│ │
│ 2. For each pending payment: │
│ ┌──────────────────────────┐ │
│ │ Generate Secure Hash │ │
│ │ - MESSAGE_ID = "2" │ │
│ │ - TRANSACTION_ID │ │
│ │ - SHA256 calculation │ │
│ └──────────┬───────────────┘ │
│ ↓ │
│ ┌──────────────────────────┐ │
│ │ Call Payment Gateway │ │
│ │ - POST to inquiry URL │ │
│ │ - Send secure hash │ │
│ └──────────┬───────────────┘ │
│ ↓ │
│ ┌──────────────────────────┐ │
│ │ Parse Response │ │
│ │ - StatusCode │ │
│ │ - StatusDescription │ │
│ │ - Card details │ │
│ └──────────┬───────────────┘ │
│ ↓ │
│ ┌──────────────────────────┐ │
│ │ Update Database │ │
│ │ - XML serialization │ │
│ │ - Update PayForData │ │
│ └──────────┬───────────────┘ │
│ ↓ │
│ ┌──────────────────────────┐ │
│ │ If StatusCode = 00000 │ │
│ │ → Authenticate API │ │
│ │ → Update Booking │ │
│ │ Status = Booked (1) │ │
│ └──────────┬───────────────┘ │
│ ↓ │
│ ┌──────────────────────────┐ │
│ │ If InquiryCount >= 3 │ │
│ │ → Cancel Booking (8) │ │
│ └──────────────────────────┘ │
│ │
└────────────────────────────────────┘
↓
GetPendingRefundPayment()
↓
GetPendingWalletPurchasedPayment()
↓
GetPendingPackagePurchasedPayment()
Refund Processing Flow¶
GetPendingRefundPayment()
↓
┌────────────────────────────────────┐
│ 1. Fetch pending refunds from DB │
│ │
│ 2. For each refund: │
│ ┌────────────────────────────┐ │
│ │ Generate New Transaction │ │
│ │ - "PSY" + Timestamp │ │
│ │ - Amount in cents │ │
│ └────────┬───────────────────┘ │
│ ↓ │
│ ┌────────────────────────────┐ │
│ │ Generate Secure Hash │ │
│ │ - MESSAGE_ID = "4" │ │
│ │ - TRANSACTION_ID (new) │ │
│ │ - AMOUNT, CURRENCY │ │
│ │ - Original TX ID │ │
│ └────────┬───────────────────┘ │
│ ↓ │
│ ┌────────────────────────────┐ │
│ │ POST to Payment Gateway │ │
│ │ - Refund endpoint │ │
│ └────────┬───────────────────┘ │
│ ↓ │
│ ┌────────────────────────────┐ │
│ │ Parse Response │ │
│ └────────┬───────────────────┘ │
│ ↓ │
│ ┌────────────────────────────┐ │
│ │ Update Refund Status in DB │ │
│ └────────┬───────────────────┘ │
│ ↓ │
│ ┌────────────────────────────┐ │
│ │ If StatusCode = 00000 │ │
│ │ → Authenticate Psyter API│ │
│ │ → Send Refund Notification│ │
│ │ to Patient & Provider │ │
│ └────────────────────────────┘ │
│ │
└────────────────────────────────────┘
FCM Notification Flow¶
Timer (10 min) → OnElapsedTimeForFCMNotificationsAndReminders()
↓
CreateThreadForSendFCMNotificationsAndReminders()
↓
GetPendingFCMNotificationsAndReminders()
↓
┌─────────────────────────────────────┐
│ Fetch from DB: │
│ - UserNotificationsList │
│ - UserRemindersList │
│ - FCMConfiguration │
└──────────────┬──────────────────────┘
↓
┌──────────────────────────────────────┐
│ For each reminder: │
│ ┌────────────────────────────────┐ │
│ │ Determine User Type │ │
│ │ UserType=1 → Patient │ │
│ │ UserType=0 → Provider │ │
│ └──────────┬─────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────┐ │
│ │ Get User's Reminder List │ │
│ │ (all reminders for booking) │ │
│ └──────────┬─────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────┐ │
│ │ Build FCM Payload │ │
│ │ - NotificationType = 12 │ │
│ │ - Booking details │ │
│ │ - User/Provider info │ │
│ │ - Reminder list │ │
│ │ - Video meeting ID │ │
│ └──────────┬─────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────┐ │
│ │ Authenticate Psyter API │ │
│ └──────────┬─────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────┐ │
│ │ POST to Psyter API │ │
│ │ /Notification/ │ │
│ │ SendNotificationWithCustomData│ │
│ └──────────┬─────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────┐ │
│ │ Mark Reminder as Sent │ │
│ │ - Update DB status │ │
│ │ - Create notification log │ │
│ └────────────────────────────────┘ │
└──────────────────────────────────────┘
Configuration Management¶
App.config Structure¶
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
</startup>
<appSettings>
<!-- API Base URLs -->
<add key="PsyterAPIBaseURL" value="..." />
<add key="SchedulingAPIBaseURL" value="..." />
</appSettings>
<connectionStrings>
<!-- Database Connection -->
<add name="PsyterDatabase"
connectionString="..."
providerName="System.Data.SqlClient"/>
</connectionStrings>
</configuration>
Database Configuration¶
Retrieved from Database:
- Payment gateway settings (Smart Routing)
- API authentication tokens
- FCM configuration
Stored in AppConfigSettings table:
SmartRoutingSecretKey
SmartRoutingResponseBackURL
RedirectToPaymentMobileToken
SmartRoutingRedirectURL
SmartRoutingMerchantId
SmartRoutingCurrencyISOCode
SmartRoutingRefundInquiryUrl
SmartRoutingThemeId
SmartRoutingVersion
SmartRoutingItemId
Integration Points¶
External Systems¶
-
Psyter API (
https://dvx.innotech-sa.com/Psyter/Master/APIs/)
- Authentication (/Authenticate)
- Refund notifications (/Notification/SendRefundBookingNotification)
- FCM notifications (/Notification/SendNotificationWithCustomData)
- SCHFS expiry (/Notification/NotifySCHFSCardExpiry) -
Scheduling API (
https://dvx.innotech-sa.com/Scheduling/SchedulingAPI/)
- Authentication (/Authenticate)
- Booking status updates (/api/Schedule/UpdateBookingStatus) -
Payment Gateway (Smart Routing)
- Inquiry/Refund endpoint (configured in DB)
- Merchant authentication
- Secure hash verification -
SQL Server Database
- 14 stored procedures
- Connection via Enterprise Library
Data Flow¶
┌──────────────────┐
│ Windows Service │
└────────┬─────────┘
│
├─────────────────────────────────┐
│ │
v v
┌─────────────────┐ ┌──────────────────┐
│ SQL Server DB │ │ External APIs │
│ │ │ │
│ - Pending │ │ - Psyter API │
│ Payments │ │ - Scheduling │
│ - Config │ │ - Payment │
│ - Notifications│ │ Gateway │
└─────────────────┘ └──────────────────┘
│ │
│ │
└────────────┬────────────────────┘
│
v
┌────────────────────────┐
│ Updated Records: │
│ - Payment Status │
│ - Booking Status │
│ - Notification Logs │
└────────────────────────┘
Error Handling Patterns¶
Thread Safety¶
- Single thread per operation type
- Thread state checking before creation
- Prevents concurrent execution of same task
Database Error Handling¶
- Try-catch blocks around all DB operations
- Exception logging to file
- Output parameters for status codes
- Boolean return values for success/failure
API Error Handling¶
- Try-catch around all HTTP calls
- SSL certificate bypass for development
- Authentication token refresh on each cycle
- Response parsing with null checks
Logging Strategy¶
- Separate log files per operation type
- Timestamped entries
- Exception details captured
- Daily log file creation
- 30-day retention policy
Security Architecture¶
Secure Hash Generation (SHA256)¶
// Build sorted dictionary
SortedDictionary<string, string> dictionary = ...
// Create ordered string
StringBuilder orderedString = new StringBuilder();
orderedString.Append(SECRECT_KEY);
foreach (KeyValuePair<string, string> kv in dictionary)
{
orderedString.Append(kv.Value);
}
// Compute SHA256
byte[] bytes = Encoding.UTF8.GetBytes(orderedString.ToString());
SHA256 sha256 = SHA256Managed.Create();
byte[] hash = sha256.ComputeHash(bytes);
// Convert to hex string
string secureHash = string.Join("", hash.Select(x => x.ToString("x2")));
Authentication Flow¶
Service Method
↓
Check if [API]AuthToken is null
↓
Call [API]AuthenticationToken()
↓
POST to /Authenticate endpoint
- applicationtoken
- grant_type=password
↓
Parse JObject response
- access_token
- refresh_token
- expires_in
↓
Store token in service property
↓
Use token in subsequent API calls
- Authorization: Bearer {token}
Sensitive Data Handling¶
Stored in App.config (Plaintext):
- Database credentials
- API base URLs
Stored in Database:
- Payment gateway secret key
- Merchant ID
- API tokens
Not Persisted:
- API access tokens (memory only)
- Card details (logged but not stored)
Performance Characteristics¶
Timer-Based Processing¶
| Operation | Frequency | Typical Duration |
|---|---|---|
| Payment Inquiry | 10 minutes | 5-30 seconds |
| Refund Processing | 10 minutes | 5-30 seconds |
| FCM Notifications | 10 minutes | 10-60 seconds |
| SCHFS Expiry | 24 hours | 1-5 seconds |
| Log Cleanup | 15 days | 1-10 seconds |
Scalability Considerations¶
Current Limitations:
- Single-threaded per operation type
- Sequential processing of pending items
- No batch database operations
- Token refresh on every cycle
Scalability Patterns Used:
- Thread pooling (via Thread class)
- Timer-based scheduling
- Asynchronous API calls (async/await)
- Connection pooling (Enterprise Library)
Code Metrics¶
Lines of Code¶
| Component | LOC (approx) |
|---|---|
| PaymentInquiryService.cs | 1,000+ |
| PaymentDataAccess.cs | 250 |
| DBHelper.cs | 120 |
| DTOs (all) | 300 |
| Total | ~1,670 |
Complexity Indicators¶
- Methods: 35+ across all classes
- Stored Procedures: 14
- Models: 20+
- Timers: 4
- Threads: 4
- External APIs: 3
- Database Tables: 10+ (estimated)
Dependencies¶
NuGet Packages: 4
- Enterprise Library (3 packages)
- Newtonsoft.Json
Framework: .NET Framework 4.8
External Services: 3
- Psyter API
- Scheduling API
- Payment Gateway
Deployment Structure¶
Installation Directory/
├── PsyterPaymentInquiry.exe # Service executable
├── PsyterPaymentInquiry.exe.config # Configuration
├── *.dll # Dependencies
│ ├── Microsoft.Practices.EnterpriseLibrary.Common.dll
│ ├── Microsoft.Practices.EnterpriseLibrary.Data.dll
│ ├── Microsoft.Practices.ObjectBuilder.dll
│ └── Newtonsoft.Json.dll
└── Logs/ # Created at runtime
├── ServiceLog_Inquiry_[Date].txt
├── ServiceLog_Refund_[Date].txt
├── ServiceLog_NotifySCHFSCardExpiry_[Date].txt
├── ServiceLog_DeleteFileLog_[Date].txt
└── ServiceLog_SendFCMNotificationAndReminders_[Date].txt
Maintenance Points¶
Regular Monitoring¶
- Service Status: Verify service is running
- Log Files: Review for errors/exceptions
- Database: Check pending payment counts
- API Connectivity: Ensure external APIs are accessible
Update Procedures¶
- Stop service
- Backup current binaries
- Deploy new version
- Update App.config if needed
- Start service
- Monitor logs
Troubleshooting Areas¶
- Database Connection: Enterprise Library database factory
- API Authentication: Token generation and refresh
- Thread Management: Thread state and lifecycle
- Payment Gateway: Secure hash generation and response parsing
Analysis Date: November 10, 2025
Analyzed By: AI Code Auditor
Service Version: Current production version