예제 #1
0
class ExerciseOutputSchema(BaseSchema):
    exercise_id = StringType(required=False, serialized_name='exerciseId')
    name = StringType(required=True, max_length=100, min_length=0)
    description = StringType(required=True, max_length=500, min_length=0)
    video_url = StringType(required=True,
                           serialized_name='videoUrl',
                           max_length=1000,
                           min_length=0)
    equipment_number = NumberType(required=True,
                                  serialized_name='equipmentNumber')
    files = ListType(field=ModelType(model_spec=ExerciseFileOutputSchema,
                                     required=False),
                     required=False)
예제 #2
0
class BaseMongoModel(Model):
    """
    Provides generic methods to work with model.
    Why use `MyModel.find_one` instead of `db.collection.find_one` ?
    1. Collection name is declared inside the model, so it is not needed
        to provide it all the time
    2. This `MyModel.find_one` will return MyModel instance, whereas
        `db.collection.find_one` will return dictionary

    Example with directly access:
        db_result = yield db.collection_name.find_one({"i": 3})
        obj = MyModel(db_result)

    Same example, but using MyModel.find_one:
        obj = yield MyModel.find_one(db, {"i": 3})

    #########################################

    Using motor with schematics simulate ORM.
    Like this:
        from schematics.types import StringType
        class NewsModel(BaseModel):
            title = StringType()
            content = StringType()
            author = StringType() 
            MONGO_COLLECTION = 'news'


    the api motor.Op is deprecated.
    # Old style:
    document = yield motor.Op(collection.find_one, {'_id': my_id})
    # New style:
    document = yield collection.find_one({'_id': my_id})
    """

    _id = NumberType(number_class=ObjectId, number_type="ObjectId")

    def __init__(self, *args, **kwargs):
        """ db settings
        虽然这边有db的属性,但是在handler里面写逻辑,有时候引用这个db不太方便,
        所以在handler里面加了db属性,直接在那边调用.
        注意各个方法,有的db是默认参数,有的db需要手动带入,使用时要注意别弄错了。
        """
        default_db = context['dbconn'].test
        self.set_db(kwargs.pop('db', default_db))
        super(BaseMongoModel, self).__init__(*args, **kwargs)

    @property
    def db(self):
        return getattr(self, '_db', None)

    def set_db(self, db):
        self._db = db

    @classmethod
    def process_query(cls, query):
        """
        query can be modified here before actual providing to database.
        """
        return dict(query)

    @property
    def pk(self):
        return self._id

    @classmethod
    def get_model_name(cls):
        return cls.MONGO_COLLECTION

    @classmethod
    def get_collection(cls):
        return getattr(cls, 'MONGO_COLLECTION', None)

    @classmethod
    def check_collection(cls, collection):
        return collection or cls.get_collection()

    @classmethod
    def find_list_len(cls):
        return getattr(cls, 'FIND_LIST_LEN', MAX_FIND_LIST_LEN)

    @classmethod
    @gen.coroutine
    def find_one(cls, db, query, collection=None, model=True):
        result = None
        c = cls.check_collection(collection)
        query = cls.process_query(query)
        for i in cls.reconnect_amount():
            try:
                result = yield db[c].find_one(query)
            except ConnectionFailure as e:
                exceed = yield cls.check_reconnect_tries_and_wait(
                    i, 'find_one')
                if exceed:
                    raise e
            else:
                if model and result:
                    result = cls.make_model(result, "find_one", db=db)
                raise gen.Return(result)

    @classmethod
    @gen.coroutine
    def remove_entries(cls, db, query, collection=None):
        """
        Removes documents by given query.
        Example:
            obj = yield ExampleModel.remove_entries(
                self.db, {"first_name": "Hello"})
        """
        c = cls.check_collection(collection)
        query = cls.process_query(query)
        for i in cls.reconnect_amount():
            try:
                yield db[c].remove(query)
            except ConnectionFailure as e:
                exceed = yield cls.check_reconnect_tries_and_wait(
                    i, 'remove_entries')
                if exceed:
                    raise e
            else:
                return

    @gen.coroutine
    def remove(self, db, collection=None):
        """
        Removes current instance from database.
        Example:
            obj = yield ExampleModel.find_one(self.db, {"last_name": "Sara"})
            yield obj.remove(self.db)
        """
        _id = self.to_primitive()['_id']
        yield self.remove_entries(db, {"_id": _id}, collection)

    @gen.coroutine
    def save(self, db=None, collection=None, ser=None):
        """
        If object has _id, then object will be created or fully rewritten.
        If not, object will be inserted and _id will be assigned.
        Example:
            obj = ExampleModel({"first_name": "Vasya"})
            yield obj.save(self.db)
        """
        db = db or self.db
        c = self.check_collection(collection)
        data = self.get_data_for_save(ser)
        result = None
        for i in self.reconnect_amount():
            try:
                result = yield db[c].save(data)
            except ConnectionFailure as e:
                exceed = yield self.check_reconnect_tries_and_wait(i, 'save')
                if exceed:
                    raise e
            else:
                if result:
                    self._id = result
                return

    @gen.coroutine
    def insert(self, db=None, collection=None, ser=None, **kwargs):
        """
        If object has _id, then object will be inserted with given _id.
        If object with such _id is already in database, then
        pymongo.errors.DuplicateKeyError will be raised.
        If object has no _id, then object will be inserted and _id will be
        assigned.

        Example:
            obj = ExampleModel({"first_name": "Vasya"})
            yield obj.insert()
        """
        db = db or self.db
        c = self.check_collection(collection)
        data = self.get_data_for_save(ser)
        for i in self.reconnect_amount():
            try:
                result = yield db[c].insert(data, **kwargs)
            except ConnectionFailure as e:
                exceed = yield self.check_reconnect_tries_and_wait(i, 'insert')
                if exceed:
                    raise e
            else:
                if result:
                    self._id = result
                return

    @gen.coroutine
    def update(self,
               db=None,
               query=None,
               collection=None,
               update=None,
               ser=None,
               upsert=False,
               multi=False):
        """
        Updates the object. If object has _id, then try to update the object.
        If object with given _id is not found in database, or object doesn't
        have _id field, then save it and assign generated _id.
        Difference from save:
            Suppose such object in database:
                {"_id": 1, "foo": "egg1", "bar": "egg2"}
            We want to save following data:
                {"_id": 1, "foo": "egg3"}
            If we'll run save, then in database will be following data:
                {"_id": 1, "foo": "egg3"} # "bar": "egg2" is removed
            But if we'll run update, then existing fields will be kept:
                {"_id": 1, "foo": "egg3", "bar": "egg2"}
        Example:
            obj = yield ExampleModel.find_one(self.db, {"first_name": "Foo"})
            obj.last_name = "Bar"
            yield obj.update(self.db)
        """
        db = db or self.db
        # TODO: refactor, update and ser arguments are very similar, left only one
        c = self.check_collection(collection)
        if update is None:
            data = self.get_data_for_save(ser)
        else:
            data = update
        if not query:
            _id = self.pk or data.pop("_id")
            query = {"_id": _id}
        if update is None:
            data = {"$set": data}
        for i in self.reconnect_amount():
            try:
                result = yield db[c].update(query,
                                            data,
                                            upsert=upsert,
                                            multi=multi)
            except ConnectionFailure as e:
                exceed = yield self.check_reconnect_tries_and_wait(i, 'update')
                if exceed:
                    raise e
            else:
                l.debug("Update result: {0}".format(result))
                raise gen.Return(result)

    @classmethod
    def get_cursor(cls, db, query, collection=None, fields={}):
        c = cls.check_collection(collection)
        query = cls.process_query(query)
        return db[c].find(query, fields) if fields else db[c].find(query)

    @classmethod
    @gen.coroutine
    def find(cls, cursor, model=True, list_len=None):
        """
        Returns a list of found documents.

        :arg cursor: motor cursor for find
        :arg model: if True, then construct model instance for each document.
            Otherwise, just leave them as list of dicts.
        :arg list_len: list of documents to be returned.

        Example:
            cursor = ExampleModel.get_cursor(self.db, {"first_name": "Hello"})
            objects = yield ExampleModel.find(cursor)
        """
        result = None
        list_len = list_len or cls.find_list_len() or MAX_FIND_LIST_LEN
        for i in cls.reconnect_amount():
            try:
                result = yield cursor.to_list(list_len)
            except ConnectionFailure as e:
                exceed = yield cls.check_reconnect_tries_and_wait(i, 'find')
                if exceed:
                    raise e
            else:
                if model:
                    field_names_set = set(cls._fields.keys())
                    for i in xrange(len(result)):
                        result[i] = cls.make_model(result[i], "find",
                                                   field_names_set)
                raise gen.Return(result)

    @classmethod
    @gen.coroutine
    def aggregate(cls, db, pipe_list, collection=None):
        c = cls.check_collection(collection)
        for i in cls.reconnect_amount():
            try:
                result = yield db[c].aggregate(pipe_list)
            except ConnectionFailure as e:
                exceed = yield cls.check_reconnect_tries_and_wait(
                    i, 'aggregate')
                if exceed:
                    raise e
            else:
                raise gen.Return(result)

    @staticmethod
    def reconnect_amount():
        return xrange(MONGO_RECONNECT_TRIES + 1)

    @classmethod
    @gen.coroutine
    def check_reconnect_tries_and_wait(cls, reconnect_number, func_name):
        if reconnect_number >= MONGO_RECONNECT_TRIES:
            raise gen.Return(True)
        else:
            timeout = MONGO_RECONNECT_TIMEOUT
            l.warning("ConnectionFailure #{0} in {1}.{2}. Waiting {3} seconds".
                      format(reconnect_number + 1, cls.__name__, func_name,
                             timeout))
            io_loop = ioloop.IOLoop.instance()
            yield gen.Task(io_loop.add_timeout, timedelta(seconds=timeout))

    def get_data_for_save(self, ser):
        data = ser or self.to_primitive()
        if '_id' in data and data['_id'] is None:
            del data['_id']
        return data

    @classmethod
    def make_model(cls, data, method_name, field_names_set=None, db=None):
        """
        Create model instance from data (dict).
        """
        if field_names_set is None:
            field_names_set = set(cls._fields.keys())
        else:
            if not isinstance(field_names_set, set):
                field_names_set = set(field_names_set)
        new_keys = set(data.keys()) - field_names_set
        if new_keys:
            l.warning("'{0}' has unhandled fields in DB: "
                      "'{1}'. {2} returned data: '{3}'".format(
                          cls.__name__, new_keys, data, method_name))
            for new_key in new_keys:
                del data[new_key]
        return cls(raw_data=data, db=db)
class BillingProfile(
        Model):  # belongs to VmScaleSet >> VirtualMachineScaleSetVMProfile
    max_price = NumberType(serialize_when_none=False)
예제 #4
0
class BaseModel(Model):
    _id = NumberType(number_class=ObjectId, number_type="ObjectId")

    def __init__(self, *args, **kwargs):
        self.errors = []
        self.set_db(kwargs.pop('db', None))
        if args and args[0].get("errors"):
            self.errors.append(args[0]['errors'])
        try:
            super(BaseModel, self).__init__(*args, **kwargs)
        except ModelConversionError as error:
            self.errors.append(error.messages)
            args_dict = args[0]
            # print("errors = ", error.messages.keys())
            # print("dict = ", args[0])
            for key in error.messages.keys():
                del args_dict[key]
            super(BaseModel, self).__init__(args_dict, *args[1:], **kwargs)

    @property
    def db(self):
        return getattr(self, '_db', None)

    def set_db(self, db):
        self._db = db

    @classmethod
    def process_query(cls, query):
        """
        query can be modified here before actual providing to database.
        """
        return dict(query)

    @classmethod
    def get_collection(cls):
        return getattr(cls, 'MONGO_COLLECTION', None)

    @classmethod
    def check_collection(cls, collection):
        return collection or cls.get_collection()

    def get_data_for_save(self, ser):
        data = ser or self.to_primitive()
        if '_id' in data and data['_id'] is None:
            del data['_id']
        return data

    @gen.coroutine
    def save(self, db=None, collection=None, ser=None):
        """
        Сохраняет объект в db
        """
        try:
            self.validate()
        except ModelValidationError as error:
            self.errors.append(error.messages)
        if self.errors:
            return
        # save Obj to DB
        db = db or self.db
        c = self.check_collection(collection)
        data = self.get_data_for_save(ser)
        # result = None
        for i in self.reconnect_amount():
            try:
                result = yield motor.Op(db[c].save, data)
            except ConnectionFailure as e:
                exceed = yield self.check_reconnect_tries_and_wait(i, 'save')
                if exceed:
                    raise e
            else:
                if result:
                    self._id = result
                return

    @classmethod
    @gen.coroutine
    def find_one(cls, db, query, collection=None, model=True):
        # result = None
        query = cls.process_query(query)
        for i in cls.reconnect_amount():
            try:
                result = yield motor.Op(
                    db[cls.check_collection(collection)].find_one, query)
            except ConnectionFailure as e:
                exceed = yield cls.check_reconnect_tries_and_wait(
                    i, 'find_one')
                if exceed:
                    raise e
            else:
                print('result = ', result)
                if model and result:
                    result = cls.make_model(result, "find_one", db=db)
                raise gen.Return(result or [])

    @staticmethod
    def reconnect_amount():
        return range(MONGO_DB['reconnect_tries'] + 1)

    @classmethod
    @gen.coroutine
    def check_reconnect_tries_and_wait(cls, reconnect_number, func_name):
        if reconnect_number >= MONGO_DB['reconnect_tries']:
            raise gen.Return(True)
        else:
            timeout = MONGO_DB['reconnect_timeout']
            l.warning("ConnectionFailure #{0} in {1}.{2}. Waiting {3} seconds".
                      format(reconnect_number + 1, cls.__name__, func_name,
                             timeout))
            io_loop = ioloop.IOLoop.instance()
            yield gen.Task(io_loop.add_timeout, timedelta(seconds=timeout))

    @classmethod
    def make_model(cls, data, method_name, field_names_set=None, db=None):
        """
        Create model instance from data (dict).
        """
        if field_names_set is None:
            field_names_set = set(cls._fields.keys())
        else:
            if not isinstance(field_names_set, set):
                field_names_set = set(field_names_set)
        new_keys = set(data.keys()) - field_names_set
        if new_keys:
            l.warning("'{0}' has unhandled fields in DB: "
                      "'{1}'. {2} returned data: '{3}'".format(
                          cls.__name__, new_keys, data, method_name))
            for new_key in new_keys:
                del data[new_key]
        return cls(raw_data=data, db=db)
예제 #5
0
class ProductGDSN(Model):
    # Col_A = StringType(default='', serialize_when_none=False)
    Label_Description = StringType(max_length=200,
                                   required=False,
                                   default='None')
    Trade_Item_GTIN = StringType(regex="\d(539|501|509|0\d\d)\d{10}",
                                 required=True)
    Product_Description = StringType(max_length=200, required=True)
    Information_Provider_GLN = StringType(regex="\d{13}", required=True)
    Information_Provider_Name = StringType(max_length=100,
                                           required=False,
                                           default='GS1 Ireland')
    Company_Name = StringType(max_length=100, required=True)

    Target_Market = StringType(choices=[tm[0] for tm in TM],
                               required=False,
                               default='372')
    Trade_Item_Country_Of_Origin = StringType(choices=[tm[0] for tm in TM],
                                              required=False,
                                              default='372')
    Use_Language_Code_List = StringType(choices=[lng[0] for lng in LANGUAGES],
                                        default='en')  # 58

    Classification_Category_Code = StringType(required=True)
    Base_Unit_Indicator = MyBooleanType(required=True)
    Consumer_Unit_Indicator = MyBooleanType(required=True)
    Variable_Weight_Trade_Item = MyBooleanType(required=True)
    Ordering_Unit_Indicator = MyBooleanType(required=True)
    Dispatch_Unit_Indicator = MyBooleanType(required=True)
    Invoice_Unit_Indicator = MyBooleanType(required=True)
    Trade_Item_Unit_Descriptor = StringType(
        choices=[d[1] for d in PACKAGE_LEVELS], required=True)
    Functional_Name = StringType(max_length=75, required=True)
    Brand_Name = StringType(max_length=75, required=True)
    Height = DecimalType(required=False)
    Width = DecimalType(required=False)
    Depth = DecimalType(required=False)
    Height_UOM = StringType(choices=[uom[0] for uom in UOMS], required=False)
    Width_UOM = StringType(choices=[uom[0] for uom in UOMS], required=False)
    Depth_UOM = StringType(choices=[uom[0] for uom in UOMS], required=False)
    Gross_Weight = DecimalType(required=False)
    Gross_Weight_UOM = StringType(choices=[uom[0] for uom in UOMS],
                                  required=False)
    Net_Content = StringType(max_length=10, required=False)
    Net_Content_UOM = StringType(choices=[uom[0] for uom in UOMS],
                                 required=False)
    Packaging_Type_Code = StringType(choices=[pt[0] for pt in PACKAGE_TYPES],
                                     required=False)

    Trade_Item_Last_Change_Date = DateTimeType(
        required=False, serialized_format="%Y-%m-%dT%H:%M:%S%zZ")
    Discontinued_Date = DateTimeType(required=False,
                                     serialized_format="%Y-%m-%dT%H:%M:%S%zZ")
    Col_AM = StringType(default='', serialize_when_none=False)

    Sub_Brand = StringType(max_length=75, required=False)
    Variant_Description = StringType(max_length=75, required=False)
    Net_Weight = DecimalType(required=False)
    Net_Weight_UOM = StringType(choices=[uom[0] for uom in UOMS],
                                required=False)
    Manufacturer_GLN = StringType(required=False)
    Manufacturer_Name = StringType(max_length=100, required=False)
    Additional_Trade_Item_Identification_Type = StringType(max_length=50,
                                                           required=False)
    Additional_Trade_Item_Identification_Value = StringType(max_length=50,
                                                            required=False)
    Type_Of_Information = StringType(max_length=100, required=False)
    Uniform_Resource_Identifier = StringType(max_length=100, required=False)
    Packaging_Marked_Returnable = MyBooleanType()
    Is_Price_On_Pack = MyBooleanType()
    GTIN_Of_Next_Lower_Item = StringType(required=False)
    Amount_Of_Next_Lower_Level_Items = StringType(required=False)
    Quantity_Of_Children = NumberType(int,
                                      'Integer',
                                      min_value=1,
                                      required=False)
    Total_Quantity_Of_Next_Lower_Level_Trade_Item = StringType(required=False)
    Start_Availability_Date_Time = DateTimeType(
        required=False, serialized_format="%Y-%m-%dT%H:%M:%S%zZ")
    End_Availability_Date_Time = DateTimeType(
        required=False, serialized_format="%Y-%m-%dT%H:%M:%S%zZ")

    Trade_Item_Status = StringType(max_length=25,
                                   required=False,
                                   default='ADD')

    Brand_Owner_GLN = StringType(required=False)
    Brand_Owner_Name = StringType(max_length=100, required=False)
    Col_AN = StringType(default='', serialize_when_none=False)
    Col_AO = StringType(default='', serialize_when_none=False)
    Col_AP = StringType(default='', serialize_when_none=False)
    Publication_Date = DateTimeType(
        required=False, serialized_format="%Y-%m-%dT%H:%M:%S%zZ")  # pub_date
    Effective_Date = DateTimeType(
        required=False, serialized_format="%Y-%m-%dT%H:%M:%S%zZ")  # eff_date
    Col_AZ = StringType(default='', serialize_when_none=False)
    Col_BA = StringType(default='', serialize_when_none=False)
    Col_BB = StringType(default='', serialize_when_none=False)
    Col_BC = StringType(default='', serialize_when_none=False)
    Col_BD = StringType(default='', serialize_when_none=False)
    Col_BE = StringType(default='', serialize_when_none=False)
    Col_BF = StringType(default='', serialize_when_none=False)
    Col_BG = StringType(default='', serialize_when_none=False)
    Col_BH = StringType(default='', serialize_when_none=False)
    Col_BI = StringType(default='', serialize_when_none=False)
    Col_BJ = StringType(default='', serialize_when_none=False)
    Col_BK = StringType(default='', serialize_when_none=False)
    Col_BL = StringType(default='', serialize_when_none=False)
    Barcode_Type = StringType(choices=[bt[0] for bt in BARCODE_TYPES],
                              required=False)
    Col_BO = StringType(default='', serialize_when_none=False)
    Col_BP = StringType(default='', serialize_when_none=False)
    Col_BQ = StringType(default='', serialize_when_none=False)
    Col_BV = StringType(default='', serialize_when_none=False)
    Col_BW = StringType(default='', serialize_when_none=False)
    Col_BX = StringType(default='', serialize_when_none=False)
    Col_BY = StringType(default='', serialize_when_none=False)
    Col_BZ = StringType(default='', serialize_when_none=False)
    Col_CA = StringType(default='', serialize_when_none=False)
    Col_CB = StringType(default='', serialize_when_none=False)
    Col_CC = StringType(default='', serialize_when_none=False)
    Col_CD = StringType(default='', serialize_when_none=False)
    Col_CE = StringType(default='', serialize_when_none=False)

    Col_CG = StringType(default='', serialize_when_none=False)
    Col_CH = StringType(default='', serialize_when_none=False)
    Col_CI = StringType(default='', serialize_when_none=False)
    Col_CJ = StringType(default='', serialize_when_none=False)
    Col_CK = StringType(default='', serialize_when_none=False)
    Col_CL = StringType(default='', serialize_when_none=False)
    Col_CM = StringType(default='', serialize_when_none=False)
    Col_CN = StringType(default='', serialize_when_none=False)
    Col_CO = StringType(default='', serialize_when_none=False)
    Col_CP = StringType(default='', serialize_when_none=False)
    Col_CQ = StringType(default='', serialize_when_none=False)
    Col_CR = StringType(default='', serialize_when_none=False)

    Col_CS = StringType(default='', serialize_when_none=False)
    Col_CT = StringType(default='', serialize_when_none=False)
    Col_CU = StringType(default='', serialize_when_none=False)
    Col_CV = StringType(default='', serialize_when_none=False)
    Col_CW = StringType(default='', serialize_when_none=False)
    Col_CX = StringType(default='', serialize_when_none=False)
    Col_CY = StringType(default='', serialize_when_none=False)
    Col_CZ = StringType(default='', serialize_when_none=False)
    Col_DA = StringType(default='', serialize_when_none=False)
    Col_DB = StringType(default='', serialize_when_none=False)
    Col_DC = StringType(default='', serialize_when_none=False)
    Col_DE = StringType(default='', serialize_when_none=False)

    GS1CloudStatus = StringType(choices=['ACTIVE', 'INACTIVE'], required=False)
    '''
    # def validate_Additional_Trade_Item_Identification_Value(self, data, value):
    #    if not value:
    #        raise ValidationError("This field is required")

    def validate_Label_Description(self, data, value):
        if data['Trade_Item_Unit_Descriptor'] == 'BASE_UNIT_OR_EACH':
            if not value:
                raise ValidationError("This field is required for base units")

    def validate_Classification_Category_Code(self, data, value):
        cs = CategoriesService()
        if self.Classification_Category_Code.required and not value:
            raise ValidationError("Classification Category Code is required")
        if value and not cs.first(code=value):
            raise ValidationError(
                "Classification Category Code is not valid, please consult https://www.gs1.org/gpc/browser")

    def validate_Manufacturer_GLN(self, data, value):
        if value and not re.match("\d{13}", value):
            raise ValidationError("Manufacturer GLN is not valid")
        if value and not data['Manufacturer_Name']:
            raise ValidationError("If Manufacturer GLN is present, Manufacturer Name should be present")

    def validate_Manufacturer_Name(self, data, value):
        if value and not data['Manufacturer_GLN']:
            raise ValidationError("If Manufacturer Name is present, Manufacturer GLN should be present")

    # def validate_Brand_Owner_GLN(self, data, value):
    #    if value and not re.match("\d{13}", value):
    #        raise ValidationError("Brand Owner GLN is not valid")

    def validate_Trade_Item_GTIN(self, data, value):
        if not isValid(value):
            raise ValidationError("GTIN not valid")

    def validate_Net_Content(self, data, value):
        if value:
            if not data.get('Net_Content_UOM'):
                raise ValidationError("Net Content is given without Net Content UOM")

    def validate_Net_Content_UOM(self, data, value):
        if value:
            if not data.get('Net_Content'):
                raise ValidationError("Net Content UOM is given without Net Content value")

    def validate_Net_Weight(self, data, value):
        if value:
            if not data.get('Net_Weight_UOM'):
                raise ValidationError("Net Weight is given without Net Weight UOM")

    def validate_Net_Weight_UOM(self, data, value):
        if value:
            if not data.get('Net_Weight'):
                raise ValidationError("Net Weight UOM is given without Net Weight value")

    def validate_Height_UOM(self, data, value):
        if data['Height'] and not value:
            raise ValidationError("Height UOM is required when Height is given")

    def validate_Width_UOM(self, data, value):
        if data['Width'] and not value:
            raise ValidationError("Width UOM is required when Width is given")

    def validate_Depth_UOM(self, data, value):
        if data['Depth'] and not value:
            raise ValidationError("Depth UOM is required when Depth is given")

    def validate_Gross_Weight_UOM(self, data, value):
        if data['Gross_Weight'] and not value:
            raise ValidationError("Gross_Weight UOM is required when Gross_Weight is given")

    def validate_Quantity_Of_Children(self, data, value):
        if data['Trade_Item_Unit_Descriptor'] != BASE_PACKAGE_LEVEL:
            if not value:
                raise ValidationError(
                    "Quantity Of Children is required when Trade Item Unit Descriptor is not BASE UNIT OR EACH")

    def validate_Quantity_Of_Next_Lower_Level_Item(self, data, value):
        if data['GTIN_Of_Next_Lower_Item']:
            if not value:
                raise ValidationError(
                    "Quantity Of Next Lower Level Item is required when GTIN Of Next Lower Item is given")
            if len(data['Quantity_Of_Next_Lower_Level_Item'].split(',')) != int(data['Quantity_Of_Children']):
                raise ValidationError("Length of Quantity Of Next Lower Level Item must equal the Quantity Of Children")

    def validate_GTIN_Of_Next_Lower_Item(self, data, value):
        if data['Trade_Item_Unit_Descriptor'] != BASE_PACKAGE_LEVEL:
            if not value:
                raise ValidationError(
                    "GTIN Of Next Lower Item is required when Trade Item Unit Descriptor is not BASE UNIT OR EACH")
            try:
                int(data['Quantity_Of_Children'])
            except Exception as e:
                raise ValidationError("Quantity_Of_Children must be given")
            if len(data['GTIN_Of_Next_Lower_Item'].split(',')) != int(data['Quantity_Of_Children']):
                raise ValidationError("Length of GTIN_Of_Next_Lower_Item must equal the Quantity Of Children")

    # def validate_fileFormatCode(self, data, value):
    #    pass

    # def validate_Uniform_Resource_Identifier(self, data, value):
    #    if value:
    #        if not value.startswith('http://') or not value.statswith('https://'):
    #            raise ValidationError('Uniform_Resource_Identifier should start with http: or https:')
    '''
    @classmethod
    def get_fieldnames(cls):
        return [
            # 'Col_A',
            'Label_Description',
            'Trade_Item_GTIN',
            'Information_Provider_GLN',
            'Information_Provider_Name',
            'Target_Market',
            'Base_Unit_Indicator',
            'Consumer_Unit_Indicator',
            'Variable_Weight_Trade_Item',
            'Ordering_Unit_Indicator',
            'Dispatch_Unit_Indicator',
            'Invoice_Unit_Indicator',
            'Start_Availability_Date_Time',
            'Classification_Category_Code',
            'Trade_Item_Unit_Descriptor',
            'Functional_Name',
            'Brand_Name',
            'Packaging_Marked_Returnable',
            'Height',
            'Height_UOM',
            'Width',
            'Width_UOM',
            'Depth',
            'Depth_UOM',
            'Gross_Weight',
            'Gross_Weight_UOM',
            'End_Availability_Date_Time',
            'Sub_Brand',
            'Brand_Owner_GLN',
            'Brand_Owner_Name',
            'Product_Description',
            'Variant_Description',
            'Net_Content',
            'Net_Content_UOM',
            'Net_Weight',
            'Net_Weight_UOM',
            'Packaging_Type_Code',
            'Trade_Item_Last_Change_Date',
            'Discontinued_Date',
            'Col_AM',  # Display_Unit_Indicator
            'Col_AN',  # Platform_Type_Code
            'Col_AO',  # Packaging_Weight
            'Col_AP',  # Packaging_Weight_UoM
            'Publication_Date',
            'Effective_Date',
            'GTIN_Of_Next_Lower_Item',
            'Amount_Of_Next_Lower_Level_Items',
            'Quantity_Of_Children',
            'Total_Quantity_Of_Next_Lower_Level_Trade_Item',
            'Trade_Item_Country_Of_Origin',
            'Manufacturer_GLN',
            'Manufacturer_Name',
            'Col_AZ',
            'Col_BA',
            'Col_BB',
            'Col_BC',
            'Col_BD',
            'Col_BE',
            'Col_BF',
            'Col_BG',
            'Col_BH',
            'Col_BI',
            'Col_BJ',
            'Col_BK',
            'Col_BL',
            'Is_Price_On_Pack',
            'Barcode_Type',
            'Col_BO',
            'Col_BP',
            'Col_BQ',
            'Additional_Trade_Item_Identification_Type',
            'Additional_Trade_Item_Identification_Value',
            'Type_Of_Information',
            'Uniform_Resource_Identifier',
            'Col_BV',
            'Col_BW',
            'Col_BX',
            'Col_BY',
            'Col_BZ',
            'Col_CA',
            'Col_CB',
            'Col_CC',
            'Col_CD',
            'Col_CE',
            'Trade_Item_Status',
            'Col_CG',
            'Col_CH',
            'Col_CI',
            'Col_CJ',
            'Col_CK',
            'Col_CL',
            'Col_CM',
            'Col_CN',
            'Col_CO',
            'Col_CP',
            'Col_CQ',
            'Col_CR',
            'Col_CS',
            'Col_CT',
            'Col_CU',
            'Col_CV',
            'Col_CW',
            'Col_CX',
            'Col_CY',
            'Col_CZ',
            'Col_DA',
            'Col_DB',
            'Col_DC',
            'Use_Language_Code_List',
            'Col_DE',
            'GS1CloudStatus',
            'Company_Name'
        ]

    @classmethod
    def export(cls, products, user):
        errors = []
        content = []
        tm = ProductTemplate.objects.filter(name="gs1se-base").first()
        keys = set(x.path.split(".")[-1] for x in tm.attributes.all())
        serialized_products = serializers.serialize('json',
                                                    products,
                                                    fields=keys)
        products_data = json.loads(serialized_products)
        xls_keys = language_mapping(tm, user)
        for product in products_data:
            try:
                res = {
                    xls_keys[key]: get_translated_values(value, user)
                    for key, value in product.get("fields").items()
                }
            except ModelConversionError as e:
                errors.append({
                    product.gtin:
                    dict([(k, v[0]) for k, v in e.messages.items()])
                })
                continue
            except Exception as e:
                errors.append({product.gtin: {'Exception': str(e)}})
                continue
            content.append(res)
        return content, errors
예제 #6
0
class Product(Model):
    year = NumberType(min_value=2018, max_value=2021, strict=False)
    # year = IntType()
    name = StringType(required=True)
    link = URLType(required=True)