Coverage for statistic/order.py: 97%

124 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-05-25 10:23 +0000

1"""Order class for managing and processing orders. 

2This class provides methods to handle order data, including 

3calculating start and finish times, checking for specific conditions, 

4and converting data types. It also maintains a count of the total 

5number of orders created. 

6""" 

7from pprint import pprint 

8# from data_drive.data_sql import get_newest_list_beton_or_lista 

9import re 

10import datetime 

11from src.settings import Settings 

12 

13 

14class Order: 

15 

16 count_ordres = 0 

17 

18 def __init__( 

19 self, date_order, metres, times, firm, name, uwagi, przebieg, tel, wenz, pompa_dzwig 

20 ): 

21 

22 self.date_order = date_order 

23 self.metres = self.convert_to_float(metres) 

24 self.times = times 

25 self.firm = self.convert_to_string(firm) 

26 self.name = self.convert_to_string(name) 

27 self.uwagi = self.convert_to_string(uwagi) 

28 self.przebieg = self.convert_to_string(przebieg) 

29 self.tel = self.convert_to_string(self.tel_to_string(tel)) 

30 self.wenz = wenz 

31 self.list_of_loads = [] 

32 self.cancellation = self.get_cancellation() 

33 self.pompa_dzwig = self.check_pompa_dzwig(pompa_dzwig, self.metres) 

34 

35 self.list_of_courses = self.get_list_courses() 

36 self.start_time = self.get_start_time() 

37 self.finish_time = self.get_finish_time_and_form_list_times_of_loads() 

38 self.it_is_zaprawa = self.check_zaprawa() 

39 self.it_is_concret = self.check_concret() 

40 self.reszta = self.get_reszta() 

41 

42 Order.count_ordres += 1 

43 

44 def tel_to_string(self, data): 

45 """converts the phone number to a string and removes any unwanted characters. 

46 

47 Args: 

48 data (any): the phone number from cell tel to be converted 

49 Returns: 

50 str: the converted phone number  

51 """ 

52 if data: 

53 if isinstance(data, float): 

54 return str(int(data)).strip() 

55 elif isinstance(data, int): 

56 return str(data).strip() 

57 elif isinstance(data, str): 

58 return data.strip() 

59 else: 

60 return "" 

61 else: 

62 return "" 

63 

64 def convert_to_float(self, data): 

65 """converts the data to a float. 

66 If the data is None, it returns 0. If the data is a string, it tries to convert it to a float. 

67 If the data is a float or int, it returns the data as a float. 

68 If the data is a string that cannot be converted to a float, it returns 0. 

69 

70 Args: 

71 data (any): raw data to be converted 

72 

73 Returns: 

74 int or float: the converted data 

75 """ 

76 if data: 

77 if isinstance(data, float): 

78 return abs(round(data, 1)) 

79 elif isinstance(data, int): 

80 return abs(float(round(data, 1))) 

81 else: 

82 return 0.0 

83 else: 

84 return 0.0 

85 

86 def convert_to_string(self, data): 

87 """converts the data to a string. 

88 If the data is None, it returns an empty string. 

89 If the data is a string, it strips any unwanted characters. 

90 

91 Args: 

92 data (any): dta from cell to be converted 

93 

94 Returns: 

95 str: the converted data 

96 """ 

97 if not data: 

98 return "" 

99 try: 

100 data = str(data) 

101 data = re.sub(r"\s+", " ", data) 

102 data = data.strip() 

103 return data 

104 except (TypeError, ValueError): 

105 return "" 

106 

107 def get_list_courses(self): 

108 """forms a list of courses based on the number of metres. 

109 The list is formed by dividing the number of metres by 8. 

110 

111 Returns: 

112 list: list of courses 

113 """ 

114 

115 if self.metres == 0: 

116 return [0,] 

117 

118 # The number of courses equivalent to 8 

119 base_value = int(self.metres // 8) 

120 

121 # A remainder of less than 8 meters 

122 remainder = self.metres % 8 

123 

124 # Initializing a list with values equal to 8 meters 

125 result = [ 

126 8.0, 

127 ] * base_value 

128 

129 # if remainder less then 2 metrs 

130 if remainder != 0 and base_value > 0 and remainder < 2: 

131 # The lasct element is adjusted to be 1 less, and added this 1 metr to remainder 

132 result[-1] -= 1 

133 remainder += 1 

134 

135 result = result + [ 

136 round(remainder, 2), 

137 ] 

138 

139 elif remainder != 0 and base_value > 0 and remainder >= 2: 

140 # if remainder greater or equal 2 metrs, just added like a last element of list  

141 result = result + [ 

142 round(remainder, 2), 

143 ] 

144 

145 elif remainder != 0 and base_value == 0: 

146 result = [ 

147 round(remainder, 2), 

148 ] 

149 

150 return result 

151 

152 def get_start_time(self): 

153 """calculates the start time of the order. 

154 The start time is calculated by subtracting 30 minutes from the order time. 

155 

156 Returns: 

157 datetime: the start time of the order 

158 """ 

159 date_order = datetime.datetime.strptime( 

160 self.date_order, "%d.%m.%Y").date() 

161 data_time_order = datetime.datetime.combine(date_order, self.times) 

162 

163 return data_time_order - datetime.timedelta(minutes=Settings.travel_to_the_construction) 

164 

165 def get_finish_time_and_form_list_times_of_loads(self): 

166 """calculates the finish time of the order. 

167 The finish time is calculated by adding the shipping duration to the start time. 

168 The shipping duration is calculated based on the number of courses and the type of pump or crane. 

169 

170 Returns: 

171 datetime: the finish time of the order 

172 """ 

173 shipping_duration = 0 

174 

175 if self.list_of_courses[0]: 

176 self.list_of_loads += [self.start_time,] 

177 else: 

178 self.list_of_loads = [] 

179 

180 for cours in self.list_of_courses[:-1]: 

181 if self.pompa_dzwig: # if it's pompa 

182 shipping_duration += cours * Settings.unloading_time_for_pomp 

183 self.list_of_loads += [self.list_of_loads[-1] + datetime.timedelta( 

184 minutes=cours * Settings.unloading_time_for_pomp),] 

185 else: 

186 shipping_duration += cours * Settings.unloading_time_for_crane # if it's crane 

187 self.list_of_loads += [self.list_of_loads[-1] + datetime.timedelta( 

188 minutes=cours * Settings.unloading_time_for_crane),] 

189 

190 return self.start_time + datetime.timedelta(minutes=shipping_duration) 

191 

192 def check_pompa_dzwig(self, pompa_dzwig, metres): 

193 """ checks if the order is for a pump or crane. 

194 If the order is for a pump, it returns True. 

195 If the order is for a crane, it returns False. 

196 

197 Args: 

198 pompa_dgwig (str): string keep infomation from excel about using pomp or  

199 "" - if no use pomp 

200 metres (float): the number of metres in the order 

201 

202 Returns: 

203 bool: True if the order is for a pump, False if it's for a crane 

204 """ 

205 if pompa_dzwig: # if it's pompa 

206 data =self.convert_to_string(pompa_dzwig) 

207 data = data.strip() 

208 # todo remove in settings '501' "pompogrusz" 

209 if data == '501': 

210 return False 

211 elif "pompogrusz" in data.lower() and metres <= 5.5: 

212 self.cancellation = True 

213 return True 

214 return True 

215 

216 elif not pompa_dzwig and metres > 50: 

217 return True 

218 

219 return False 

220 

221 def check_zaprawa(self): 

222 """checks if the order is for zaprawa. 

223 If the order is for zaprawa, it returns True. 

224 

225 Returns: 

226 bool: True if the order is for zaprawa, False otherwise 

227 """ 

228 if ( 

229 self.list_of_courses[0] < Settings.amount_of_zaprawa 

230 and self.times < Settings.time_of_end_upload_zaprawa 

231 and not re.search(Settings.names_dry_concret, self.name) 

232 ): 

233 return True 

234 return False 

235 

236 def check_concret(self): 

237 """checks if the order is for concret. 

238 If the order is for concret, it returns True, not dry concret 

239 

240 Returns: 

241 bool: True if the order is for concret, False otherwise 

242 """ 

243 

244 if re.search(Settings.names_dry_concret, self.name): 

245 return False 

246 return True 

247 

248 def get_reszta(self): 

249 reszta = [] 

250 metres = self.metres 

251 

252 for cours in self.list_of_courses: 

253 reszta.append(metres - cours) 

254 metres -= cours 

255 

256 return reszta 

257 

258 def get_cancellation(self): 

259 concat_uwagi = self.uwagi + self.przebieg 

260 

261 if "odwo" in concat_uwagi.lower(): 

262 return True 

263 

264 return False 

265 

266 

267 @classmethod 

268 def how_many(cls): 

269 """Prints the current population.""" 

270 print("We have {:d} orders.".format(cls.count_ordres)) 

271 return "We have {:d} orders.".format(cls.count_ordres) 

272 

273 

274if __name__ == "__main__": 

275 pass 

276 

277 # # pprint(get_newest_list_beton_or_lista("beton", "03.02.2025")[5]) 

278 

279 # # bud = Order(*get_newest_list_beton_or_lista("beton", "03.02.2025")[5]) 

280 # # bud1 = Order(*get_newest_list_beton_or_lista("beton", "03.02.2025")[9]) 

281 # # bud2 = Order(*get_newest_list_beton_or_lista("beton", "03.02.2025")[3]) 

282 # orders = {} 

283 # count = 1 

284 # date_order = "07.02.2025" 

285 # for item in get_newest_list_beton_or_lista("beton", date_order, 'zawod'): 

286 # orders[f"{count}bud"] = Order(date_order, *item) 

287 # count += 1 

288 

289 # pprint(orders) 

290 

291 # df_bud = [] 

292 # for key_bud in orders.keys(): 

293 # bud = orders[key_bud] 

294 # pprint( 

295 # ( 

296 # bud.name, 

297 # bud.metres, 

298 # bud.times, 

299 # bud.start_time, 

300 # bud.finish_time, 

301 # bud.list_of_loads, 

302 # bud.it_is_zaprawa, 

303 # bud.it_is_concret, 

304 # bud.list_of_courses, 

305 # bud.date_order, 

306 # bud.count_ordres, 

307 # ) 

308 # ) 

309 # df_bud.append({ 

310 # "name": bud.name, 

311 # "metr": bud.metres, 

312 # "time": bud.times, 

313 # "start_time": bud.start_time, 

314 # "finish_time": bud.finish_time, 

315 # "list_of_loads": bud.list_of_loads, 

316 # "it_is_zaprawa": bud.it_is_zaprawa, 

317 # "it_is_concret": bud.it_is_concret, 

318 # "list_of_courses": bud.list_of_courses, 

319 # "date_order": bud.date_order, 

320 # "date_order": bud.date_order, 

321 # })