Exporting harvest log is not including quantity and inventory?

Quantity values not getting on exported harvest log.

1 Like

That’s true. It’s a limitation of the log CSV exports right now. But I would like to add that as a next step.

This is where the code recently changed: Improve asset and log CSV exports by mstenta · Pull Request #783 · farmOS/farmOS · GitHub

Specifically, in the “Next steps”:

The log exports do not contain quantity data. This will require a custom normalizer. I didn’t have time to do that in this round, but should be a pretty easy followup once we have some resources for it.

If you are interested in helping with this, we would welcome the contribution!

I would be more than happy to contribute. please let me know the next steps.

I had been a codeignite3 + php full stack developer for past 2yrs.

Thank you so much.

1 Like

This is where we put our custom CSV normalizers: farmOS/modules/core/csv/src/Normalizer at 3.x · farmOS/farmOS · GitHub

And this submit function is where the serialization occurs: farmOS/modules/core/export/modules/csv/src/Form/EntityCsvActionForm.php at 0156283a6361e9c59aa357008fde8b478b3ab09b · farmOS/farmOS · GitHub

I think the trickiest part about quantities is that you can have many quantities on a single log, so we may only decide to show the first one in the log CSV export. The quantity export is where you can get all quantities as separate rows.

1 Like

That would be great @aathi179! Here is some more general information about how serialization works in Drupal (which use’s Symfony’s serialization logic underneath):

1 Like

Hi @mstenta ,I just modified some lines(aathi code start to aathi code end) in this file in local environment like below. Now, Quantity export working.Here, I only export first quantity value.

<?php

namespace Drupal\farm_csv\Normalizer;

use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\serialization\Normalizer\ContentEntityNormalizer as CoreContentEntityNormalizer;

/**
 * Normalizes farmOS content entities for CSV exports.
 */
class ContentEntityNormalizer extends CoreContentEntityNormalizer {

  /**
   * The supported format.
   */
  const FORMAT = 'csv';

  /**
   * {@inheritdoc}
   */
  public function normalize($entity, $format = NULL, array $context = []): array|string|int|float|bool|\ArrayObject|NULL {
    $data = parent::normalize($entity, $format, $context);
    // If columns were explicitly included, remove others.
	
	//aathi code start
	$name = "quantity";
	if(isset($data[$name])){
	  $quantity = "";
	  $quantity_measure = "";
	  $quantity_units = [["value" => 0]];
	  $quantity_label = "";
	  $tempquantarr = [];
	  if(!empty($data[$name])){
		  $entity_type_id = 'quantity'; 
			$entity_id = $data[$name][0];
			$quantity_entity = \Drupal::entityTypeManager()->getStorage($entity_type_id)->load($entity_id);
			$unit_ids = $quantity_entity->get('units')->getValue();
			if(!empty($unit_ids)){
				$unitid = $unit_ids[0]["target_id"];
				$unit_type_id = "taxonomy_term";
				$term = \Drupal::entityTypeManager()->getStorage($unit_type_id)->load($unitid);
				if ($term->hasField("name")) {
				  $quantity_units = $term->get("name")->getValue();
				}
			}
			$temp_quan = $quantity_entity->get('value')->getValue();
			if(!empty($temp_quan)){
				$quantity = [["value" => (int)$temp_quan[0]["numerator"]/(int)$temp_quan[0]["denominator"]]];
			}else{
				$quantity = [["value" => 0]];
			}
			
			$quantity_measure = $quantity_entity->get('measure')->getValue();
			$quantity_label = $quantity_entity->get('label')->getValue();
	  }
	    $tempquantarr[$name] = $quantity;
		$tempquantarr["quantity measure"] = $quantity_measure;
		$tempquantarr["quantity units"] = $quantity_units;
		$tempquantarr["quantity label"] = $quantity_label;
		
		$arrayEnd = array_splice($data, array_search($name, array_keys($data)));
		unset($arrayEnd[$name]);
		
		$data = $data + $tempquantarr + $arrayEnd;
	}
	array_push($context['include_columns'],"quantity","quantity measure","quantity units","quantity label");
	//aathi code end
	
    if (!empty($context['include_columns'])) {
      foreach (array_keys($data) as $key) {
        if (!in_array($key, $context['include_columns'])) {
          unset($data[$key]);
        }
      }
    }

    return $data;
  }

  /**
   * {@inheritdoc}
   */
  public function supportsNormalization($data, string $format = NULL, array $context = []): bool {
    return $data instanceof ContentEntityInterface && $format == static::FORMAT;
  }

}

But, we need to import two quantity at one time. now i am trying to import two quantities per log record.currently, FarmOS can import only one quantity per log record.

Thank you.

1 Like

That’s a good way to experiment @aathi179! Well done!

But… be aware that if you make any changes to farmOS core code, it will be lost when you upgrade, unless you maintain your changes somehow. I’m sure you already know that, but I didn’t want you to lose anything.

The best way to make changes is usually by creating a custom module that uses Drupal hooks/event subscribers to alter/modify behavior. Then you can commit your module to source control and maintain it separately from farmOS, so it doesn’t block your farmOS upgrades. A lot of things can be modified from a module… but not everything. I’m not sure if this could be packaged in a module or not.

The other way to maintain it is to save this to a branch that you keep updated as new releases of farmOS are made. The best thing, though, would be to open a pull request so your changes could be included in farmOS core itself! Then you don’t need to maintain anything. :slight_smile:

If you wanted to pursue a pull request, I would probably suggest taking a different approach with this code. This is currently modifying the ContentEntityNormalizer (for the log entity itself), and then loading quantity entities. I think a better approach would be to create a separate normalizer for the quantity reference field itself. It would probably work similar to the other reference fields. For example, when you export a log, it includes an asset column which shows the names of assets that are referenced by the log. Ideally, we could show a quantity column that summarized the quantities that are referenced. If I were doing that, I would investigate how the asset column normalization happens and mimic that.

But… there are still bigger questions to answer. If we only include 1 quantity, then the usefulness is limited. But if we include multiple, where do we stop? What happens if a log had 100+ quantities?

The same question could be asked of the asset field too… but at least with assets we are only showing the asset name. With a quantity there is more information that might be necessary, and including that in a way that is useful is hard.

I don’t have a good answer for this. Which is also why I would hesitate to suggest opening a PR… there may be disagreement on the “right” way to do this.

On the other hand… if you need something more custom, you could also consider building a View that includes multiple columns for the quantities you need, with it’s own simple CSV export feature.

There is a balance here: it may be that we can create a general solution that doesn’t solve every problem (like the current exporters), but there is flexibility to create more customized exports for specific purposes (eg: if you know there are exactly 2 quantities you want every time).

1 Like

Yes that’s true. I would suggest starting a different topic for that, since the import code is completely separate from the export code. But if you are experimenting, take a look at this: CSV importers | farmOS

1 Like

@mstenta , thank you. Will look for alternative approach.

Thank you

1 Like