@@ -285,81 +285,67 @@ class Meta:
285285 )
286286
287287 def validate (self , data ):
288- full_data = self ._get_full_data (data )
288+ """
289+ Main validation method.
290+ Determines the mode and calls the corresponding validation method.
291+ """
289292
290- mode = full_data .get ('mode' )
293+ mode = data .get ('mode' , getattr ( self . instance , 'mode' , None ) )
291294
292295 if mode == business .constants .PROMO_MODE_COMMON :
293- self ._validate_common (full_data )
294-
296+ self ._validate_common (data )
295297 elif mode == business .constants .PROMO_MODE_UNIQUE :
296- self ._validate_unique (full_data )
297-
298+ self ._validate_unique (data )
299+ elif mode is None :
300+ raise rest_framework .serializers .ValidationError (
301+ {'mode' : 'This field is required.' },
302+ )
298303 else :
299304 raise rest_framework .serializers .ValidationError (
300305 {'mode' : 'Invalid mode.' },
301306 )
302307
303308 return data
304309
305- def to_representation (self , instance ):
306- """
307- Controls the display of fields in the response.
308- """
309- data = super ().to_representation (instance )
310-
311- if not instance .image_url :
312- data .pop ('image_url' , None )
313-
314- if instance .mode == business .constants .PROMO_MODE_UNIQUE :
315- data .pop ('promo_common' , None )
316- if 'promo_unique' in self .fields and isinstance (
317- self .fields ['promo_unique' ],
318- rest_framework .serializers .SerializerMethodField ,
319- ):
320- data ['promo_unique' ] = self .get_promo_unique (instance )
321- else :
322- data ['promo_unique' ] = [
323- code .code for code in instance .unique_codes .all ()
324- ]
325- else :
326- data .pop ('promo_unique' , None )
327-
328- return data
329-
330- def _get_full_data (self , data ):
331- """
332- Build the full data dict by merging existing instance data
333- with new input.
334- """
335- if self .instance :
336- full_data = self .to_representation (self .instance )
337- full_data .update (data )
338- else :
339- full_data = data
340- return full_data
341-
342- def _validate_common (self , full_data ):
310+ def _validate_common (self , data ):
343311 """
344312 Validations for COMMON promo mode.
345313 """
346- promo_common = full_data .get ('promo_common' )
347- promo_unique = full_data .get ('promo_unique' )
348- max_count = full_data .get ('max_count' )
349314
350- if not promo_common :
315+ if 'promo_unique' in data and data [ 'promo_unique' ] is not None :
351316 raise rest_framework .serializers .ValidationError (
352- {'promo_common ' : 'This field is required for COMMON mode.' },
317+ {'promo_unique ' : 'This field is not allowed for COMMON mode.' },
353318 )
354319
355- if promo_unique is not None :
320+ if self . instance is None and not data . get ( 'promo_common' ) :
356321 raise rest_framework .serializers .ValidationError (
357- {'promo_unique ' : 'This field is not allowed for COMMON mode.' },
322+ {'promo_common ' : 'This field is required for COMMON mode.' },
358323 )
359324
325+ new_max_count = data .get ('max_count' )
326+ if self .instance and new_max_count is not None :
327+ used_count = self .instance .get_used_codes_count
328+ if used_count > new_max_count :
329+ raise rest_framework .serializers .ValidationError (
330+ {
331+ 'max_count' : (
332+ f'max_count ({ new_max_count } ) cannot be less than '
333+ f'used_count ({ used_count } ).'
334+ ),
335+ },
336+ )
337+
338+ effective_max_count = (
339+ new_max_count
340+ if new_max_count is not None
341+ else getattr (self .instance , 'max_count' , None )
342+ )
343+
360344 min_c = business .constants .PROMO_COMMON_MIN_COUNT
361345 max_c = business .constants .PROMO_COMMON_MAX_COUNT
362- if not (min_c <= max_count <= max_c ):
346+ if effective_max_count is not None and not (
347+ min_c <= effective_max_count <= max_c
348+ ):
363349 raise rest_framework .serializers .ValidationError (
364350 {
365351 'max_count' : (
@@ -368,35 +354,67 @@ def _validate_common(self, full_data):
368354 },
369355 )
370356
371- def _validate_unique (self , full_data ):
357+ def _validate_unique (self , data ):
372358 """
373359 Validations for UNIQUE promo mode.
374360 """
375- promo_common = full_data .get ('promo_common' )
376- promo_unique = full_data .get ('promo_unique' )
377- max_count = full_data .get ('max_count' )
378361
379- if not promo_unique :
362+ if 'promo_common' in data and data [ 'promo_common' ] is not None :
380363 raise rest_framework .serializers .ValidationError (
381- {'promo_unique ' : 'This field is required for UNIQUE mode.' },
364+ {'promo_common ' : 'This field is not allowed for UNIQUE mode.' },
382365 )
383366
384- if promo_common is not None :
367+ if self . instance is None and not data . get ( 'promo_unique' ) :
385368 raise rest_framework .serializers .ValidationError (
386- {'promo_common ' : 'This field is not allowed for UNIQUE mode.' },
369+ {'promo_unique ' : 'This field is required for UNIQUE mode.' },
387370 )
388371
389- if max_count != business .constants .PROMO_UNIQUE_MAX_COUNT :
372+ effective_max_count = data .get (
373+ 'max_count' ,
374+ getattr (self .instance , 'max_count' , None ),
375+ )
376+
377+ if (
378+ effective_max_count is not None
379+ and effective_max_count
380+ != business .constants .PROMO_UNIQUE_MAX_COUNT
381+ ):
390382 raise rest_framework .serializers .ValidationError (
391383 {
392384 'max_count' : (
393385 'Must be equal to '
394- f'{ business .constants .PROMO_UNIQUE_MAX_COUNT } '
386+ f'{ business .constants .PROMO_UNIQUE_MAX_COUNT } '
395387 'for UNIQUE mode.'
396388 ),
397389 },
398390 )
399391
392+ def to_representation (self , instance ):
393+ """
394+ Controls the display of fields in the response.
395+ """
396+
397+ data = super ().to_representation (instance )
398+
399+ if not instance .image_url :
400+ data .pop ('image_url' , None )
401+
402+ if instance .mode == business .constants .PROMO_MODE_UNIQUE :
403+ data .pop ('promo_common' , None )
404+ if 'promo_unique' in self .fields and isinstance (
405+ self .fields ['promo_unique' ],
406+ rest_framework .serializers .SerializerMethodField ,
407+ ):
408+ data ['promo_unique' ] = self .get_promo_unique (instance )
409+ else :
410+ data ['promo_unique' ] = [
411+ code .code for code in instance .unique_codes .all ()
412+ ]
413+ else :
414+ data .pop ('promo_unique' , None )
415+
416+ return data
417+
400418
401419class PromoCreateSerializer (BasePromoSerializer ):
402420 url = rest_framework .serializers .HyperlinkedIdentityField (
0 commit comments