code: def add_charge(account_id: str,
                 amount: Money,
                 reverses_id: Optional[str] = None,
                 product_code: Optional[str] = None,
                 product_properties: Optional[Dict[str, str]] = None) -> Charge:
      
      logger.info('adding-charge', account_id=account_id, amount=amount, product_code=product_code,
                  product_properties=product_properties)
  
      with transaction.atomic():
          charge = Charge(account_id=account_id,
                          amount=amount)
          if reverses_id:
              charge.reverses_id = reverses_id
          if product_code:
              charge.product_code = product_code
          charge.full_clean(exclude=['id', 'account'])  # Exclude to avoid unnecessary db queries
          charge.save(force_insert=True)
  
          if product_properties:
              objs = [ProductProperty(charge=charge, name=k, value=v) for k, v in product_properties.items()]
              for o in objs:
                  o.full_clean(exclude=['id', 'charge'])  # Exclude to avoid unnecessary db queries
              ProductProperty.objects.bulk_create(objs)
  
      return charge
docs: Add a charge to the account.
  
      :param account_id: The account on which to add the charge
      :param amount:  The amount of the charge
      :param reverses_id: Set this if this charge reverses another one
      :param product_code: A code identifying the type of product cnarged
      :param product_properties: A dict of hames and values.
      :return: The newly created charge.