Esempio n. 1
0
def reconcile_new(config, args):
    reconciliation_uploader = ReconciliationUploader(config)

    tracking_output = TrackingOutput(config)
    trackings = tracking_output.get_existing_trackings()
    reconcilable_trackings = [t for t in trackings if t.reconcile]
    # start from scratch
    all_clusters = []
    clusters.update_clusters(all_clusters, reconcilable_trackings)

    order_info_retriever = OrderInfoRetriever(config)
    fill_billed_costs('Fetching order costs', all_clusters,
                      order_info_retriever, True)
    all_clusters = clusters.merge_orders(all_clusters)
    fill_billed_costs('Filling merged order costs', all_clusters,
                      order_info_retriever, False)

    # add manual PO entries (and only manual ones)
    reconciliation_uploader.override_pos_and_costs(all_clusters)

    driver_creator = DriverCreator()
    group_site_manager = GroupSiteManager(config, driver_creator)

    trackings_to_cost, po_to_cost = get_new_tracking_pos_costs_maps(
        config, group_site_manager, args)

    clusters_by_tracking = map_clusters_by_tracking(all_clusters)
    merge_by_trackings_tuples(clusters_by_tracking, trackings_to_cost,
                              all_clusters)

    fill_costs_new(clusters_by_tracking, trackings_to_cost, po_to_cost, args)

    fill_cancellations(all_clusters, config)
    reconciliation_uploader.download_upload_clusters_new(all_clusters)
Esempio n. 2
0
def run_add(config):
    print("Add tracking to existing tracking/order cluster.")
    existing_tracking_num = get_required(
        "Enter a tracking number of the existing cluster: ")
    tracking_output = TrackingOutput(config)
    tracking = tracking_output.get_tracking(existing_tracking_num)
    if not tracking:
        print("Error: Tracking does not exist. Aborting.")
        return
    print("Existing tracking data is:")
    print(tracking)
    new_tracking_num = get_optional(
        "Enter new tracking number (or blank to abort): ")
    if not new_tracking_num:
        print("Aborting.")
        return
    tracking.tracking_number = new_tracking_num
    print("New tracking data is:")
    print(tracking)
    submit = get_required_from_options("Save?", ['y', 'n'])
    if submit:
        tracking_output.save_trackings([tracking])
        print("Saved.")
    else:
        print("Cancelled.")
Esempio n. 3
0
def run_auto(config, args):
    if not args.tracking or not args.order or not args.group:
        raise Exception(
            'Must provide tracking, order, and group if doing auto')

    orders = set()
    orders.add(args.order)
    tracking = Tracking(args.tracking, args.group, orders, '', '', '', TODAY,
                        0.0, '', '')
    print(tracking)
    tracking_output = TrackingOutput(config)
    tracking_output.save_trackings([tracking], overwrite=True)
Esempio n. 4
0
def filter_orders(orders_list, config):
  tracking_output = TrackingOutput(config)
  seen_order_ids = set()
  for tracking in tracking_output.get_existing_trackings():
    seen_order_ids.update(tracking.order_ids)

  cancelled_items_retriever = CancelledItemsRetriever(config)
  cancellations_by_order = cancelled_items_retriever.get_cancelled_items()

  result = []
  for order in orders_list:
    if order.order_id not in seen_order_ids and order.order_id not in cancellations_by_order:
      result.append(order)

  return result
Esempio n. 5
0
def run_new(config):
    print("Manual input of Tracking object.")
    print("Optional fields will display a default in brackets if one exists.")
    print("")
    tracking_output = TrackingOutput(config)
    tracking_number = get_required("Tracking number: ")
    tracking = tracking_output.get_tracking(tracking_number)
    if tracking:
        print("This tracking number already exists:")
        print(tracking)
        print("Adding new order(s) to the existing tracking number.")
    orders_to_costs = input_orders()
    if tracking:
        order_ids_set = set(tracking.order_ids)
        order_ids_set.update(orders_to_costs.keys())
        tracking.order_ids = list(order_ids_set)
        tracking.price = ''  # Zero out price for reconcile to fix later.
    else:
        ship_date = get_optional_with_default(
            "Optional ship date, formatted YYYY-MM-DD [%s]: " % TODAY, TODAY)
        group = get_required("Group, e.g. mysbuyinggroup: ")
        email = get_optional("Optional email address: ")
        order_url = get_optional("Optional order URL: ")
        merchant = get_optional("Optional merchant: ")
        description = get_optional("Optional item descriptions: ")
        tracking = Tracking(tracking_number, group,
                            set(orders_to_costs.keys()), '', email, order_url,
                            ship_date, 0.0, description, merchant)

    print("Resulting tracking object: ")
    print(tracking)
    print("Order to cost map: ")
    print(orders_to_costs)
    submit = get_required_from_options("Submit? 'y' to submit, 'n' to quit: ",
                                       ['y', 'n'])
    if submit == 'y':
        tracking_output.save_trackings([tracking], overwrite=True)
        print("Wrote tracking")
        order_info_retriever = OrderInfoRetriever(config)
        order_info_retriever.orders_dict.update(orders_to_costs)
        order_info_retriever.flush()
        print("Wrote billed amounts")
        print("This will be picked up on next reconciliation run.")
    elif submit == 'n':
        print("Submission cancelled.")
Esempio n. 6
0
def run_delete(config):
    print("Manual deletion of Tracking object.")
    tracking_number = get_required("Tracking number: ")
    tracking_output = TrackingOutput(config)
    existing_trackings = tracking_output.get_existing_trackings()

    found_list = [
        tracking for tracking in existing_trackings
        if tracking.tracking_number == tracking_number
    ]
    if found_list:
        to_delete = found_list[0]
        print("This is the Tracking object: %s" % to_delete)
        submit = get_required_from_options(
            "Are you sure you want to delete this tracking?", ['y', 'n'])
        if submit == 'y':
            existing_trackings.remove(to_delete)
            tracking_output._write_merged(existing_trackings)
        else:
            print("Deletion stopped.")
    else:
        print("Could not find that tracking number.")
Esempio n. 7
0
def reconcile_new(config, args):
  reconciliation_uploader = ReconciliationUploader(config)

  tracking_output = TrackingOutput(config)
  trackings = tracking_output.get_existing_trackings()
  reconcilable_trackings = [t for t in trackings if t.reconcile]
  # start from scratch
  all_clusters = []
  clusters.update_clusters(all_clusters, reconcilable_trackings)

  order_info_retriever = OrderInfoRetriever(config)
  fill_billed_costs('Fetching order costs', all_clusters, order_info_retriever, True)
  all_clusters = clusters.merge_orders(all_clusters)
  fill_billed_costs('Filling merged order costs', all_clusters, order_info_retriever, False)

  # add manual PO entries (and only manual ones)
  reconciliation_uploader.override_pos_and_costs(all_clusters)

  driver_creator = DriverCreator()
  group_site_manager = GroupSiteManager(config, driver_creator)

  trackings_to_info, po_to_cost = get_new_tracking_pos_costs_maps(config, group_site_manager, args)

  clusters_by_tracking = map_clusters_by_tracking(all_clusters)
  merge_by_trackings_tuples(clusters_by_tracking, trackings_to_info, all_clusters)

  fill_costs_new(clusters_by_tracking, trackings_to_info, po_to_cost, args)

  fill_cancellations(all_clusters, config)
  et(config, all_clusters)
  sheet_id = config['reconciliation']['baseSpreadsheetId']
  if args.groups:
    print("Skipping unknown-tracking upload due to the --groups argument")
  else:
    upload_unknown_trackings(sheet_id, set(clusters_by_tracking.keys()), trackings_to_info)
  reconciliation_uploader.download_upload_clusters_new(all_clusters)
Esempio n. 8
0
def run_add(config):
    new_trackings = []
    print("Add tracking to existing tracking/order cluster.")
    tracking_output = TrackingOutput(config)
    while True:
        existing_tracking_num = get_optional(
            "Enter the tracking number of the existing cluster (or blank to finish): "
        )
        if not existing_tracking_num:
            break
        tracking = tracking_output.get_tracking(existing_tracking_num)
        if not tracking:
            print("Error: Tracking does not exist. Aborting.")
            continue
        print("Existing tracking data is:")
        print(tracking)
        new_tracking_num = get_optional(
            "Enter new tracking number (or blank to abort): ")
        if not new_tracking_num:
            print("Aborting.")
            continue
        tracking.tracking_number = new_tracking_num
        print("New tracking data is:")
        print(tracking)
        submit = get_required_from_options("Save?", ['y', 'n'])
        if submit:
            new_trackings.append(tracking)
            print("Saved.")
        else:
            print("Cancelled.")

    if len(new_trackings) > 0:
        print(f"Saving {len(new_trackings)} new tracking(s) and quitting.")
        tracking_output.save_trackings(new_trackings)
    else:
        print("No new trackings to save; quitting.")
def main():
    parser = argparse.ArgumentParser(description='Get tracking #s script')
    parser.add_argument("--seen", action="store_true")
    parser.add_argument("--days")
    args, _ = parser.parse_known_args()

    driver_creator = DriverCreator()

    config = open_config()
    email_config = config['email']
    email_sender = EmailSender(email_config)

    print("Retrieving Amazon tracking numbers from email ...")
    amazon_tracking_retriever = AmazonTrackingRetriever(
        config, args, driver_creator)
    try:
        trackings = amazon_tracking_retriever.get_trackings()
    except:
        send_error_email(email_sender, "Error retrieving Amazon emails")
        raise

    print("Retrieving Best Buy tracking numbers from email ...")
    bestbuy_tracking_retriever = BestBuyTrackingRetriever(
        config, args, driver_creator)
    try:
        trackings.update(bestbuy_tracking_retriever.get_trackings())
    except:
        send_error_email(email_sender, "Error retrieving Best Buy emails")
        raise

    try:
        tracking_output = TrackingOutput(config)
        existing_tracking_nos = set([
            t.tracking_number
            for t in tracking_output.get_existing_trackings()
        ])
        new_tracking_nos = set(
            trackings.keys()).difference(existing_tracking_nos)
        print(f"Found {len(new_tracking_nos)} new tracking numbers "
              f"(out of {len(trackings)} total) from emails.")
        new_trackings = [trackings[n] for n in new_tracking_nos]

        # We only need to process new tracking numbers if there are any;
        # otherwise skip straight to processing existing locally stored data.
        if new_trackings:
            try:
                email_sender.send_email(new_trackings)
            except Exception as e:
                # When running --seen, we're often processing a very large number of emails that can
                # take a long time, and the Tracking Numbers email isn't too important to us (but the
                # upload to portals/Sheets definitely is). So don't fail after we've been running for
                # a long time just on account of a failed email.
                if args.seen:
                    print(
                        f"Email sending failed with error: {str(e)}\n{util.get_traceback_lines()}"
                    )
                    print("New trackings are:\n" +
                          "\n".join([str(nt) for nt in new_trackings]))
                    print(
                        "Continuing to portal/Sheet upload because email sending is non-essential."
                    )
                else:
                    raise e

        print("Uploading all tracking numbers...")
        group_site_manager = GroupSiteManager(config, driver_creator)
        try:
            group_site_manager.upload(trackings.values())
        except:
            send_error_email(email_sender, "Error uploading tracking numbers")
            if args.seen:
                print("Error uploading tracking numbers; skipping.")
            else:
                raise

        reconcilable_trackings = [t for t in new_trackings if t.reconcile]

        # Also only add new trackings to the sheet
        print("Adding results to Google Sheets")
        tracking_uploader = TrackingUploader(config)
        try:
            tracking_uploader.upload_trackings(reconcilable_trackings)
        except:
            send_error_email(email_sender, "Error uploading to Google Sheets")
            if args.seen:
                print("Error uploading to Google Sheets; skipping.")
            else:
                raise

        print("Writing results to file")
        try:
            tracking_output.save_trackings(new_trackings)
        except:
            send_error_email(email_sender, "Error writing output file")
            raise
        print("Done")
    except:
        print("Exception thrown after looking at the emails.")
        if not args.seen:
            print("Marking all relevant emails as unread to reset.")
        amazon_tracking_retriever.back_out_of_all()
        bestbuy_tracking_retriever.back_out_of_all()
        if not args.seen:
            print("Marked all as unread.")
        raise
Esempio n. 10
0
def main():
    parser = argparse.ArgumentParser(
        description='Importing Amazon reports from CSV or Drive')
    parser.add_argument("--personal",
                        "-p",
                        action="store_true",
                        help="Use the personal CSV format")
    parser.add_argument("globs", nargs="*")
    args, _ = parser.parse_known_args()

    from_row_function = from_personal_row if args.personal else from_amazon_row
    all_trackings = []
    if args.globs:
        for glob_input in args.globs:
            files = glob.glob(glob_input)
            for file in files:
                all_trackings.extend(
                    read_trackings_from_file(file, from_row_function))
    else:
        sheet_id = get_required("Enter Google Sheet ID: ")
        tab_name = get_required("Enter the name of the tab within the sheet: ")
        objects_to_sheet = ObjectsToSheet()
        all_trackings.extend(
            objects_to_sheet.download_from_sheet(from_amazon_row, sheet_id,
                                                 tab_name))

    if len(all_trackings) == 0:
        print("Nothing to import; terminating.")
        return

    num_n_a_trackings = len([
        ignored for ignored in all_trackings
        if ignored and ignored.tracking_number == 'N/A'
    ])
    num_empty_trackings = len([
        ignored for ignored in all_trackings
        if ignored and ignored.tracking_number == ''
    ])
    print(f'Skipping {num_n_a_trackings} for N/A tracking column and '
          f'{num_empty_trackings} for empty tracking column.')
    all_trackings = [
        tracking for tracking in all_trackings
        if tracking and tracking.tracking_number != 'N/A'
        and tracking.tracking_number != ''
    ]
    len_non_reconcilable_trackings = len(
        [t for t in all_trackings if not t.reconcile])
    print(
        f'Skipping {len_non_reconcilable_trackings} non-reconcilable trackings.'
    )
    all_trackings = [t for t in all_trackings if t.reconcile]
    base_len_trackings = len(all_trackings)
    all_trackings = dedupe_trackings(all_trackings)
    print(
        f'Filtered {base_len_trackings - len(all_trackings)} duplicate trackings from the sheet.'
    )

    print('Uploading trackings to Sheets...')
    tracking_uploader = TrackingUploader(config)
    tracking_uploader.upload_trackings(all_trackings)

    tracking_output = TrackingOutput(config)
    trackings_before_save = {
        t.tracking_number
        for t in tracking_output.get_existing_trackings()
    }
    print(f"Number of trackings before: {len(trackings_before_save)}.")
    print(f"Number imported from report(s): {len(all_trackings)}.")
    tracking_output.save_trackings(all_trackings)
    trackings_after_save = {
        t.tracking_number: t
        for t in tracking_output.get_existing_trackings()
    }
    print(f"Number of trackings after: {len(trackings_after_save)}.")
    new_trackings = set(
        trackings_after_save.keys()).difference(trackings_before_save)
    print(f"Number of new-to-us trackings: {len(new_trackings)}")

    new_tracking_objects = [trackings_after_save[t] for t in new_trackings]
    email_config = config['email']
    email_sender = EmailSender(email_config)
    email_sender.send_email(new_tracking_objects)

    print("Uploading new trackings to the group(s)' site(s)...")
    group_site_manager = GroupSiteManager(config, DriverCreator())
    group_site_manager.upload(new_tracking_objects)
Esempio n. 11
0
def main():
    parser = argparse.ArgumentParser(
        description='Importing Amazon reports from CSV or Drive')
    parser.add_argument("globs", nargs="*")
    args, _ = parser.parse_known_args()

    all_trackings = []
    if args.globs:
        for glob_input in args.globs:
            files = glob.glob(glob_input)
            for file in files:
                all_trackings.extend(read_trackings_from_file(file))
    else:
        sheet_id = get_required("Enter Google Sheet ID: ")
        tab_name = get_required("Enter the name of the tab within the sheet: ")
        objects_to_sheet = ObjectsToSheet()
        all_trackings.extend(
            objects_to_sheet.download_from_sheet(from_amazon_row, sheet_id,
                                                 tab_name))

    num_n_a_trackings = len([
        ignored for ignored in all_trackings
        if ignored and ignored.tracking_number == 'N/A'
    ])
    num_empty_trackings = len([
        ignored for ignored in all_trackings
        if ignored and ignored.tracking_number == ''
    ])
    print(
        f'Skipping {num_n_a_trackings} for n/a tracking column and {num_empty_trackings} for empty tracking column'
    )
    all_trackings = [
        tracking for tracking in all_trackings
        if tracking and tracking.tracking_number != 'N/A'
        and tracking.tracking_number != ''
    ]
    len_non_reconcilable_trackings = len(
        [t for t in all_trackings if not t.reconcile])
    print(
        f'Skipping {len_non_reconcilable_trackings} non-reconcilable trackings'
    )
    all_trackings = [t for t in all_trackings if t.reconcile]
    base_len_trackings = len(all_trackings)
    all_trackings = dedupe_trackings(all_trackings)
    print(
        f'Filtered {base_len_trackings - len(all_trackings)} duplicate trackings from the sheet'
    )

    print('Uploading trackings to Sheets...')
    tracking_uploader = TrackingUploader(config)
    tracking_uploader.upload_trackings(all_trackings)

    tracking_output = TrackingOutput(config)
    print("Number of trackings beforehand: %d" %
          len(tracking_output.get_existing_trackings()))
    print("Number from sheet: %d" % len(all_trackings))
    tracking_output.save_trackings(all_trackings)
    print("Number of trackings after: %d" %
          len(tracking_output.get_existing_trackings()))

    print("Uploading to the group(s)' site(s)...")
    group_site_manager = GroupSiteManager(config, DriverCreator())
    group_site_manager.upload(all_trackings)