File size: 5,696 Bytes
ffa1f50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
"""
Constants module for Supply Roster Optimization Tool
Replaces hard-coded magic numbers with meaningful named constants
"""
from src.preprocess import extract

class ShiftType:
    """
    Shift type constants to replace magic numbers
    1 = Regular, 2 = Evening, 3 = Overtime
    """
    REGULAR = 1
    EVENING = 2 
    OVERTIME = 3
    
    # All available shifts
    ALL_SHIFTS = [REGULAR, EVENING, OVERTIME]
    
    # Common shift combinations
    REGULAR_AND_OVERTIME = [REGULAR, OVERTIME]  # Normal mode (no evening)
    
    @classmethod
    def get_name(cls, shift_id):
        """Get human-readable name for shift ID"""
        names = {
            cls.REGULAR: "Regular",
            cls.EVENING: "Evening", 
            cls.OVERTIME: "Overtime"
        }
        return names.get(shift_id, "Unknown")
    
    @classmethod
    def get_all_names(cls):
        """Get dictionary mapping shift IDs to names"""
        return {
            cls.REGULAR: "Regular",
            cls.EVENING: "Evening", 
            cls.OVERTIME: "Overtime"
        }

class LineType:
    """
    Line type constants to replace magic numbers
    6 = Long Line, 7 = Mini Load
    """
    LONG_LINE = 6
    MINI_LOAD = 7
    
    # All available line types
    ALL_LINE_TYPES = [LONG_LINE, MINI_LOAD]
    
    @classmethod
    def get_name(cls, line_id):
        """Get human-readable name for line type ID"""
        names = {
            cls.LONG_LINE: "Long Line",
            cls.MINI_LOAD: "Mini Load"
        }
        return names.get(line_id, "Unknown")
    
    @classmethod
    def get_all_names(cls):
        """Get dictionary mapping line type IDs to names"""
        return {
            cls.LONG_LINE: "Long Line",
            cls.MINI_LOAD: "Mini Load"
        }

class KitLevel:
    """
    Kit hierarchy level constants
    0 = Prepack, 1 = Subkit, 2 = Master
    """
    PREPACK = 0
    SUBKIT = 1
    MASTER = 2
    
    # All available levels
    ALL_LEVELS = [PREPACK, SUBKIT, MASTER]
    
    @classmethod
    def get_name(cls, level_id):
        """Get human-readable name for kit level ID"""
        names = {
            cls.PREPACK: "prepack",
            cls.SUBKIT: "subkit", 
            cls.MASTER: "master"
        }
        return names.get(level_id, "unknown")
    
    @classmethod
    def get_all_names(cls):
        """Get dictionary mapping level IDs to names"""
        return {
            cls.PREPACK: "prepack",
            cls.SUBKIT: "subkit", 
            cls.MASTER: "master"
        }
    
    # Removed get_timing_weight method - no longer needed
    # Dependency ordering is now handled by topological sorting

class PaymentMode:
    """
    Payment mode constants
    """
    BULK = "bulk"
    PARTIAL = "partial"
    
    @classmethod
    def get_all_modes(cls):
        """Get all available payment modes"""
        return [cls.BULK, cls.PARTIAL]

# Default configurations using constants
class DefaultConfig:
    """Default configuration values using constants"""
    
    # Default payment modes by shift
    PAYMENT_MODE_CONFIG = {
        ShiftType.REGULAR: PaymentMode.BULK,
        ShiftType.EVENING: PaymentMode.BULK,
        ShiftType.OVERTIME: PaymentMode.PARTIAL
    }
    
    # Default max hours per shift per person
    MAX_HOUR_PER_SHIFT_PER_PERSON = {
        ShiftType.REGULAR: 7.5,
        ShiftType.EVENING: 7.5,
        ShiftType.OVERTIME: 5
    }
    
    # Default max parallel workers per line type
    MAX_PARALLEL_WORKERS = {
        LineType.LONG_LINE: 15,
        LineType.MINI_LOAD: 15
    }
    
    # Default minimum UNICEF fixed-term employees per day
    FIXED_MIN_UNICEF_PER_DAY = 2
    
    # Default line counts
    LINE_COUNT_LONG_LINE = 3
    LINE_COUNT_MINI_LOAD = 2
    
    # Default max parallel workers per line (for UI)
    MAX_PARALLEL_WORKERS_LONG_LINE = 7
    MAX_PARALLEL_WORKERS_MINI_LOAD = 5
    
    # Default cost rates (example values)
    DEFAULT_COST_RATES = {
        "UNICEF Fixed term": {
            ShiftType.REGULAR: 43.27,
            ShiftType.EVENING: 43.27,
            ShiftType.OVERTIME: 64.91
        },
        "Humanizer": {
            ShiftType.REGULAR: 27.94,
            ShiftType.EVENING: 27.94,
            ShiftType.OVERTIME: 41.91
        }
    }
    #get employee type list from data files
    EMPLOYEE_TYPE_LIST =extract.read_employee_data()["employment_type"].unique().tolist()
    SHIFT_LIST = extract.get_shift_info()["id"].unique().tolist()
    EVENING_SHIFT_MODE = "normal"
    EVENING_SHIFT_DEMAND_THRESHOLD = 0.9
    
    # Default schedule type
    SCHEDULE_TYPE = "weekly"
    
    # Default fixed staff mode
    FIXED_STAFF_MODE = "priority"
    
    # Default hourly rates for UI (simplified)
    UNICEF_RATE_SHIFT_1 = 12.5
    UNICEF_RATE_SHIFT_2 = 15.0
    UNICEF_RATE_SHIFT_3 = 18.75
    HUMANIZER_RATE_SHIFT_1 = 10.0
    HUMANIZER_RATE_SHIFT_2 = 12.0
    HUMANIZER_RATE_SHIFT_3 = 15.0
    LINE_LIST = extract.read_packaging_line_data()["id"].unique().tolist()
    LINE_CNT_PER_TYPE = extract.read_packaging_line_data().set_index("id")["line_count"].to_dict()
    
    # Dynamic method to get max employee per type on day
    @staticmethod
    def get_max_employee_per_type_on_day(date_span):
        """Get max employee per type configuration for given date span"""
        return {
            "UNICEF Fixed term": {
                t: 8 for t in date_span
            },
            "Humanizer": {
                t: 10 for t in date_span
            }
        }
    MAX_UNICEF_PER_DAY = 8
    MAX_HUMANIZER_PER_DAY = 10
    MAX_HOUR_PER_PERSON_PER_DAY = 14
    KIT_LEVELS, KIT_DEPENDENCIES, PRODUCTION_PRIORITY_ORDER = extract.get_production_order_data()